home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / asprog.EXE / BAT2EXEC.ASM next >
Assembly Source File  |  1996-07-05  |  153KB  |  3,999 lines

  1.         page    66,132
  2. ;============================================================================
  3. ; BAT2EXEC.COM - a batch file compiler
  4. ;
  5. ; Syntax:
  6. ;    BAT2EXEC filename
  7. ;
  8. ; Revision History:
  9. ;
  10. ;    Version 1.0    Initial Release     PC Magazine Vol 9 Num 14
  11. ;
  12. ;    Version 1.1    Bug Fixes               July 19, 1990
  13. ;
  14. ;    Version 1.2    Bug Fixes               July 28, 1990
  15. ;                       Added ability to read large BAT files.
  16. ;
  17. ;       Version 1.3     PATH cmd fix.           Oct.  3, 1990
  18. ;             Echo cmd fix
  19. ;                       Other small bug fixes.
  20. ;
  21. ;       Version 1.4     Redirection to soft     May. 12, 1991
  22. ;                       parameter bug fixed.
  23. ;
  24. ;       Version 1.5     Fixed lost label bug    June 20, 1991
  25. ;                       Parse like BAT files
  26. ;
  27. ;============================================================================
  28.  
  29.         code    segment
  30.         assume    cs:code
  31.  
  32.         org    2ch
  33. local_environment    dw    ?        ;Word containing the segment
  34.                         ;  of the program's env. block.
  35.         org    80h
  36. command_tail    db    ?            ;Offset of the command tail.
  37.  
  38.         org    100h
  39.  
  40. main:        jmp    initialize
  41. program     db    13,10,"BAT2EXEC 1.5 "
  42. copyright    db    "(c) 1990, 1991 Ziff Communications Co.",10,13
  43. author        db    "PC Magazine ",254," Douglas Boling"
  44.         db    10,13,"$",1Ah
  45. ;----------------------------------------------------------------------------
  46. ;Equates used to find data offsets in the compiled program.
  47. ;----------------------------------------------------------------------------
  48. BUFF_SIZE        equ    255            ;Size of runtime buffers
  49.  
  50. std_data_size    equ    offset data_end - data_start
  51. code_start_ptr    equ    [bp + offset code_start - offset data_start]
  52. com_stack_ptr    equ    [bp + offset stack_ptr - offset data_start]
  53. com_prog_size    equ    [bp + offset prog_segsize - offset data_start]
  54. com_label_start equ    [bp + offset label_list_strt - offset data_start]
  55. parse_buff    equ    [bp + offset prse_buff_ptr - offset data_start]
  56. parse2_buff    equ    [bp + offset prs2_buff_ptr - offset data_start]
  57. exec_buff    equ    [bp + offset exec_buff_ptr - offset data_start]
  58. forloop_buff    equ    [bp + offset for_buff_ptr - offset data_start]
  59. forloop_ptr    equ    [bp + offset floop_ptr - offset data_start]
  60. stdout_hdl    equ    [bp + offset file_handle1 - offset data_start]
  61. outfile_hdl    equ    [bp + offset file_handle2 - offset data_start]
  62. stdin_hdl    equ    [bp + offset file_handle3 - offset data_start]
  63. infile_hdl    equ    [bp + offset file_handle4 - offset data_start]
  64. environment_seg equ    [bp + offset master_env - offset data_start]
  65. dos_version    equ    [bp + offset version_num - offset data_start]
  66. process_rc    equ    [bp + offset proc_rc - offset data_start]
  67. shift_count    equ    [bp + offset shift_cnt - offset data_start]
  68.  
  69. code_call_size    equ    offset code_call_end - offset code_call
  70. code_jmp_size    equ    offset code_jmp_end - offset code_jmp
  71. code_jc_size    equ    offset code_jc_end - offset code_jc
  72. code_jnc_size    equ    offset code_jnc_end - offset code_jnc
  73. code_jmpdis_size   equ       offset code_jmpdis_end - offset code_jmpdis
  74. code_leasi_size equ    offset code_leasi_end - offset code_leasi
  75. code_movsi_size equ    offset code_movsi_end - offset code_movsi
  76. code_movsiim_size equ    offset code_movsiim_end - offset code_movsiim
  77. code_leadi_size equ    offset code_leadi_end - offset code_leadi
  78. code_movdi_size equ    offset code_movdi_end - offset code_movdi
  79. code_movdiim_size equ    offset code_movdiim_end - offset code_movdiim
  80. ;============================================================================
  81. ;Compiler data
  82. ;============================================================================
  83. command_table    db    "IF",0                  ;Commands processed by
  84.         db    "REM",0                 ;  compiler
  85.         db    "FOR",0
  86.         db    "ECHO",0
  87.         db    "GOTO",0
  88.         db    "EXIT",0
  89.         db    "PAUSE",0
  90.         db    "SHIFT",0
  91.         db    "SET",0
  92.         db    "CALL",0
  93.         db    "PATH",0
  94.         db    "PROMPT",0
  95.         db    "CD",0                  ;DOS commands internal to
  96.         db    "MD",0                  ;  command.com.
  97.         db    "RD",0
  98.         db    "CLS",0
  99.         db    "DIR",0
  100.         db    "DEL",0
  101.         db    "REN",0
  102.         db    "VER",0
  103.         db    "VOL",0
  104.         db    "CTTY",0
  105.         db    "CHCP",0
  106.         db    "TYPE",0
  107.         db    "COPY",0
  108.         db    "DATE",0
  109.         db    "TIME",0
  110.         db    "ERASE",0
  111.         db    "CHDIR",0
  112.         db    "MKDIR",0
  113.         db    "RMDIR",0
  114.         db    "BREAK",0
  115.         db    "RENAME",0
  116.         db    "DELETE",0
  117.         db    "VERIFY",0
  118.         db    "COMMAND",0,0
  119.  
  120. batcmd_jmptbl    dw    if_cmd            ;if command
  121.         dw    rem_cmd         ;rem command
  122.         dw    for_cmd         ;for command
  123.         dw    echo_cmd        ;echo command
  124.         dw    goto_cmd        ;goto command
  125.         dw    rem_cmd         ;exit command
  126.         dw    pause_cmd        ;pause command
  127.         dw    shift_cmd        ;shift command
  128.         dw    set_cmd         ;set command
  129.  
  130.         dw    internal_cmd        ;call command
  131.         dw    path_cmd         ;Path command
  132.         dw    prompt_cmd         ;Prompt command
  133.         dw    internal_cmd        ;DOS internal command
  134.         dw    external_cmd        ;DOS program
  135.         dw    label_cmd        ;Process BAT label
  136. batcmd_jmptbl1    =    $
  137.  
  138. ifstr1        db    "ERRORLEVEL"
  139. ifstr2        db    "EXIST"
  140.  
  141. internal_cmdsw    db    "/C "                   ;Switch for transient commands
  142.  
  143. for_active_flag db    0            ;Set if parsing a FOR loop
  144. goto_active    db    0            ;Set if goto parsed
  145. goto_data_ptr    dw    0            ;Data offset of last goto
  146.  
  147. temp1        dw    0            ;Temp data storage.
  148.  
  149. cmd_switches    db    ?            ;Used if command line switches
  150. cmd_switch_end    =    $            ;  needed.
  151.  
  152. last_routine    dw    offset init_code_next    ;Last canned routine used.
  153.  
  154. codebuff_start    dw    0            ;Buffer to construct the code
  155. codebuff_ptr    dd    0            ;  image of the COM file.
  156.  
  157. databuff_start    dw    ?            ;Buffer to hold the data
  158. databuff_end    dw    ?            ;  image of the COM file.
  159.  
  160. firstlabel    dw    -1            ;Ptr to 1st label in COM file
  161.  
  162. outbuff_ptr    dd    0            ;Buffer to hold the final
  163. outbuff_end    dw    0            ;  image of the COM file.
  164.  
  165. quote_flag    db    0            ;Disable translate flag
  166. redirect_in    db    0            ;Input redirection flag
  167. redirect_out    db    0            ;Output redirection flag
  168.  
  169. pipe_toggle    db    0            ;Piping file flag
  170. pipein_file    dw    0
  171. pipein_flag    db    0
  172. pipeout_file    dw    0
  173. pipeout_flag    db    0
  174. pipe1_file    dw    0
  175.         db    "T^M^P_$1.!!!",0    ;Name of piping file 1
  176. pipe2_file    dw    0
  177.         db    "T^M^P_$2.!!!",0    ;Name of piping file 2
  178.  
  179. inbuff_ptr    dw    offset end_of_code+512    ;Buffer for BAT file
  180. inbuff_size    dw    1024             ;Size of input buffer
  181.  
  182. file_handle    dw    -1            ;Handle of BAT file
  183. file_linecount    dw    0            ;Line number being processed.
  184.  
  185. com_string    db    ".COM",0        ;Extension for output file
  186. outfile_name    db    13 dup (" ")        ;Name of output file.
  187.  
  188. filemsg1    db    13,10,"Error in line $" ;File identification message.
  189.  
  190. errmsg0     db    "Need DOS 2.0 or greater$"
  191. errmsg1     db    13,10,"Syntax: BAT2EXEC filename.ext",13,10,"$"
  192. errmsg2     db    "Can",39,"t find input file$"
  193. errmsg3     db    "Not enough memory$"
  194. errmsg4     db    "No input file specified$"
  195. errmsg5     db    "COM file size too big$"
  196. errmsg6     db    "Syntax error$"
  197. errmsg7     db    "Compiler data buffer full$"
  198. errmsg8     db    "Label defined more than once$"
  199. errmsg9     db    "Label "
  200. errmsg9labl    db    8 dup (" ")
  201.         db    "not found$"
  202. errmsg10    db    "Illegal disk specified$"
  203. errmsg11    db    "FOR loops cannot be nested$"
  204.  
  205. endmsg        db    13,10,"$"
  206.  
  207. ;----------------------------------------------------------------------------
  208. ; Start of compiler code.
  209. ;----------------------------------------------------------------------------
  210. initialize    proc    near
  211.         assume    cs:code,ds:code,es:code
  212.         mov    dx,offset program    ;Display copyright message.
  213.         mov    ah,9
  214.         int    21h
  215.         cld                ;Set string operations 'up.'
  216.         mov    ah,30h            ;Get DOS version, run only
  217.         int    21h            ;  if 2.0 or greater.
  218.         xchg    al,ah            ;Swap major, minor numbers
  219.         mov    dx,offset errmsg0    ;Bad DOS version
  220.         cmp    ah,2
  221.         jb    jmp_disp_error
  222.  
  223.         mov    sp,offset end_of_code + 512    ;Move stack
  224.         mov    ah,4ah                ;Reduce memory
  225.         mov    bx,1000h            ; allocation to 64K
  226.         int    21h
  227.  
  228.         mov    ax,inbuff_ptr        ;Compute start of buffer for
  229.         add    ax,inbuff_size        ;  COM file data.
  230.         mov    databuff_start,ax
  231.  
  232.         mov    ah,48h            ;Allocate memory block for
  233.         mov    bx,1000h        ;  intermediate buffer.
  234.         int    21h
  235.         mov    dx,offset errmsg3    ;Not enough memory msg
  236.         jc    jmp_disp_error
  237.         mov    word ptr codebuff_ptr[2],ax    ;Save segment.
  238.  
  239.         mov    ah,48h            ;Allocate memory block for
  240.         mov    bx,1000h        ;  output file buffer.
  241.         int    21h
  242.         jc    jmp_disp_error
  243.         mov    word ptr outbuff_ptr[2],ax    ;Save segment.
  244. ;
  245. ;Parse the command line for switches.
  246. ;
  247.         mov    si,offset command_tail
  248.         xor    cx,cx
  249.         or    cl,[si]         ;Get command line length
  250.         je     init_0                  ;If zero, report no filename
  251.         inc    si
  252. parse_cmdline_l1:
  253.         xor    bl,bl            ;Search for the next
  254.         call    scan4char        ;  non-space character.
  255.         jnc    init_1                  ;If zero, report no filename
  256. init_0:
  257.         mov    dx,offset errmsg1
  258.         jmp    short jmp_disp_error    ;If none, report no filename
  259. init_1:
  260.         mov    al,[si]
  261.         cmp    al,"/"                  ;See if command switch
  262.         je    parse_error
  263.         call    loadbatfile        ;Load input BAT file
  264.         jc    jmp_disp_error
  265.         jmp    short parse_cmdline_end
  266. parse_error:
  267.         mov    dx,offset errmsg2
  268. jmp_disp_error:
  269.         jmp    disp_error
  270. parse_cmdline_end:
  271. ;
  272. ;Compile BAT file line by line.
  273. ;
  274.         mov    si,inbuff_ptr        ;SI points to input BAT file
  275.         mov    di,databuff_start    ;DI points to COM file data.
  276.         add    di,std_data_size    ;Make room for std data set.
  277. new_line:
  278.         inc    file_linecount        ;Inc line number
  279. new_line1:
  280.         xor    bl,bl            ;Look for 1st character
  281.         call    scan4char        ;If nothing on line, check
  282.         jc    comp_endcheck        ;  for EOF
  283.         call    redirect_check
  284.         cmp    byte ptr [si],'@'    ;See if non echo prefix
  285.         jne    comp_1
  286.         inc    si            ;Move past @
  287. comp_1:
  288.         call    parse            ;Parse 1st word in the line.
  289.         jc     jmp_disp_error
  290.         jmp    short new_line
  291. comp_endcheck:
  292.         cmp    al,13            ;See if carrage return, if so
  293.         je    new_line        ;  continue.
  294.         cmp    file_handle,-1        ;If at end of buffer, check
  295.         je    comp_end        ;  to see if any more of the
  296.         call    loadbatfile        ;  file to read.
  297.         jc    jmp_disp_error
  298.         mov    si,inbuff_ptr        ;Reset SI to start of buffer.
  299.         jmp    short new_line1
  300. comp_end:
  301. ;
  302. ;Inline code complete, append terminate code.
  303. ;
  304.         call    redirect_close
  305.         mov    databuff_end,di     ;Save ptr to end of data.
  306.         les    di,codebuff_ptr
  307.         assume    es:nothing
  308.         mov    si,offset end_code    ;Append terminate code
  309.         mov    cx,offset end_code_end-offset end_code
  310.         rep    movsb
  311.         mov    word ptr codebuff_ptr,di ;Save ptr to end of COM code.
  312. ;
  313. ;File processed. Assemble data and code into one routine.  Start by
  314. ;stringing the canned routines together using the links set by the
  315. ;INCLUDE routine.
  316. ;
  317.         les    di,outbuff_ptr         ;Get ptr to output buffer
  318.         mov    si,offset init_code_next ;  for COM file.
  319. file_1:     mov    cx,[si-2]        ;Get size of routine
  320.         push    [si]            ;Save pointer to next routine
  321.         add    si,4            ;Skip past number of links
  322.         rep    movsb            ;Copy routine to COM file.
  323.         pop    si
  324.         or    si,si            ;See if last routine
  325.         jne    file_1            ;No, loop back.
  326. ;
  327. ;Save starting offset of data to be used by the COM program.
  328. ;
  329.         mov    bp,offset data_start_ptr-offset init_code
  330.         mov    ax,100h         ;AX = end pointer
  331.         add    ax,di            ;Add length of canned routines.
  332.         mov    es:[bp],ax        ;Save data start pointer
  333.         mov    bp,di            ;Use BP as starting data offset
  334.  
  335.         mov    si,databuff_start    ;Compute length of COM data
  336.         mov    cx,databuff_end     ;  plus the canned routines.
  337.         sub    cx,si
  338.         add    ax,cx            ;Add data length to end ptr
  339. ;
  340. ;Now that we have the length of the canned routines and the data, we can
  341. ;compute the starting offset of the inline code.  Use this number to adjust
  342. ;the jump table entries in the label list.  While fixing offsets check to
  343. ;see that all labels have code offsets, if not, print no label error msg.
  344. ;When complete, append data to file.
  345. ;
  346.         mov    bx,offset firstlabel    ;Get pointer to the first label
  347.         mov    dx,[bx]         ;Get offset to 1st label entry
  348.         add    dx,bx            ;Add in BX to get absolute off
  349. file_11:
  350.         cmp    word ptr [bx],-1    ;See if at end of label list.
  351.         je    file_13
  352.         add    bx,[bx]         ;Get next in list
  353.         cmp    word ptr [bx+2],-1    ;See if label ptr to code
  354.         je    file_12         ;  initialized. No, error.
  355.         add    [bx+2],ax        ;Add starting offset of code
  356.         jmp    short file_11
  357. file_12:
  358.         mov    si,bx            ;Label not defined as a
  359.         add    si,5            ;  destination.  Print error
  360.         xor    cx,cx            ;  message inc lost label.
  361.         mov    cl,[bx+4]        ;Get size of label
  362.         push    cs
  363.         pop    es
  364.         mov    di,offset errmsg9labl
  365.         rep    movsb
  366.         mov    dx,offset errmsg9    ;Label not found msg
  367.         jmp    disp_error
  368. file_13:
  369.         rep    movsb            ;Append data to COM file.
  370.         sub    dx,databuff_start    ;Set pointer to 1st label list
  371.         mov    es:com_label_start,dx    ;Initialize pointer.
  372. ;
  373. ;Append the inline code to the program.
  374. ;
  375.         mov    ax,100h
  376.         add    ax,di
  377.         mov    es:code_start_ptr,ax    ;Save offset of main code.
  378.  
  379.         mov    cx,word ptr codebuff_ptr
  380.         mov    si,codebuff_start    ;Get pointer to code
  381.         mov    ds,word ptr codebuff_ptr[2]
  382.         assume    ds:nothing
  383.         sub    cx,si            ;Get size of code
  384.         add    ax,cx            ;Make sure canned routines
  385.         jnc    file_2            ;  and data < 64 K bytes.
  386. file_too_big:    mov    dx,offset errmsg5    ;COM file too big msg
  387.         jmp    disp_error
  388. file_2:
  389.         rep    movsb            ;Append inline code.
  390. ;
  391. ;Compute the size of the data buffers and the stack used by the COM program.
  392. ;Write these numbers to the COM file data area.
  393. ;
  394.         push    cs
  395.         pop    ds
  396.         assume    ds:code
  397.         add    ax,512            ;Add room for stack
  398.         jc    file_too_big
  399.         and    ax,0fffeh        ;Set stack on even word.
  400.         mov    es:com_stack_ptr,ax    ;Save run time stack pointer
  401.         add    ax,2            ;Make room for buff length word
  402.         mov    es:parse_buff,ax    ;Save ptr to parsing buffer.
  403.         add    ax,BUFF_SIZE+2        ;Add room for buffer 2
  404.         jc    file_too_big
  405.         mov    es:parse2_buff,ax    ;Save ptr to parsing buffer 2
  406.         add    ax,BUFF_SIZE+2        ;Add room for buffer
  407.         jc    file_too_big
  408.         mov    es:exec_buff,ax        ;Save ptr to exec buffer
  409.         add    ax,BUFF_SIZE+2        ;Add room for buffer
  410.         jc    file_too_big
  411.         mov    es:forloop_buff,ax    ;Save ptr to For loop buffer
  412.         add    ax,BUFF_SIZE        ;Add room for buffer
  413.         jc    file_too_big
  414.  
  415.         mov    outbuff_end,di        ;Save end pointer to file
  416.         add    ax,15
  417.         jc    file_3            ;Compute size of COM file
  418.         mov    cl,4            ;  in paragraphs.
  419.         shr    ax,cl
  420.         mov    es:com_prog_size,ax    ;Save file size
  421.         mov    byte ptr es:shift_count,0    ;Clear shift count
  422.         mov    byte ptr es:process_rc,0    ;Clear return code
  423. file_3:
  424. ;
  425. ;Write file to disk.
  426. ;
  427.         mov    ah,3ch            ;Create file
  428.         xor    cx,cx            ;Normal attributes
  429.         mov    dx,offset outfile_name    ;Name of file
  430.         int    21h
  431.  
  432.         mov    bx,ax            ;Copy handle
  433.         mov    ah,40h            ;Write file
  434.         push    ds
  435.         lds    dx,outbuff_ptr        ;Get start of buffer
  436.         mov    cx,cs:[outbuff_end]    ;Get number of bytes to write
  437.         sub    cx,dx
  438.         int    21h            ;Write file to disk
  439.         pop    ds
  440.  
  441.         mov    ah,3eh            ;Close file
  442.         int    21h
  443. ;
  444. ;Compile complete. Clean up and end.
  445. ;
  446. good_exit:
  447.         xor    al,al            ;Return code = 0
  448. exit:
  449.         push    ax            ;Save return code
  450.         mov    ah,49h            ;Release memory block used
  451.         mov    es,word ptr cs:[codebuff_ptr+2] ;  for file buffer.
  452.         int    21h
  453.  
  454.         mov    bx,file_handle
  455.         cmp    bx,-1            ;See if input file closed.
  456.         jne    exit_1            ;  If not, do so.
  457.         mov    ah,3eh            ;Close file.
  458.         int    21h
  459. exit_1:
  460.         pop    ax            ;Get back return code
  461.         mov    ah,4Ch            ;Terminate
  462.         int    21h
  463. ;
  464. ;Display error message.
  465. ;
  466. disp_error:
  467.         push    cs
  468.         pop    ds
  469.         assume    ds:code
  470.         cmp    file_linecount,0
  471.         je    disp_error1        ;If processing a file, print
  472.         push    dx            ;  a message informing the
  473.         mov    dx,offset filemsg1    ;  user the line that
  474.         call    printmsg        ;  contained the error.
  475.         mov    ax,file_linecount
  476.         call    hex2asc
  477.         mov    dx,offset endmsg
  478.         call    printmsg
  479.         pop    dx
  480. disp_error1:
  481.         call    printmsgcr        ;print string
  482.         mov    al,01            ;Terminate with RC = 1
  483.         jmp    short exit
  484.  
  485. ;-----------------------------------------------------------------------------
  486. ; PARSE  Parse a statment.
  487. ; Entry:  SI - Pointer to string to parse.
  488. ;      DI - Pointer to end of COM file data.
  489. ; Exit:   CF - Set if error.
  490. ;      SI - Updated.
  491. ;-----------------------------------------------------------------------------
  492. parse        proc    near
  493.         mov    bx,14
  494.         mov    al,[si]         ;See if label, if so, skip
  495.         cmp    al,":"            ;  cmd search.
  496.         je    parse_2
  497.  
  498.         mov    bx,12
  499.         cmp    al,"%"                  ;See if cmd line param or env
  500.         je    parse_2         ;  var. If so, internal cmd
  501.  
  502.         mov    ax,[si+1]        ;See if change to default disk
  503.         cmp    al,":"
  504.         jne    parse_1
  505.  
  506.         mov    bx, 12            ;Set internal command.
  507.         cmp    ah," "
  508.         jbe    parse_2
  509. parse_1:
  510.         call    capsalpha        ;Capitalize batch command
  511.         push    di            ;Search list of BAT cmds.
  512.         mov    di,offset command_table
  513.         call    findstr
  514.         pop    di
  515. parse_2:
  516.         push    bx            ;Scan past command except for
  517.         cmp    bx,8            ;  external progs, inter cmds,
  518.         ja    parse_3         ;  and labels.
  519.         mov    bl,1
  520.         call    scan4char
  521.         jnc    parse_3         ;If end of line, back up to
  522.         dec    si            ;  show CR.
  523. parse_3:
  524.         pop    bx
  525.         shl    bx,1            ;Compute offset of routine to
  526.         add    bx,offset batcmd_jmptbl ;  call.
  527.         call    [bx]            ;Call routine to compile line.
  528.         ret
  529. parse        endp
  530.  
  531. ;-----------------------------------------------------------------------------
  532. ; FINDSTR  determines if a string is in a list.
  533. ; Entry:  SI - Pointer to ASCII string to find.
  534. ;      DI - Pointer to list of ASCIIZ strings.
  535. ;      CX - Size of string
  536. ; Exit:   CF - Clear if string found
  537. ;      BX - If CF clear, index into list
  538. ;-----------------------------------------------------------------------------
  539. findstr     proc    near
  540.         push    cx
  541.         push    es
  542.         push    cs            ;Point ES:DI to table of
  543.         pop    es            ;  batch commands.
  544.         xor    dx,dx
  545.         or     dx,cx            ;Save length of string
  546.         je    finds_3
  547.         xor    bx,bx            ;Zero index counter
  548. finds_1:
  549.         push    si
  550.         mov    cx,dx            ;Restore command size
  551.         repe    cmpsb            ;Compare command
  552.         pop    si
  553.         jne    finds_11
  554.         cmp    byte ptr [di],0        ;See if at end of compare str
  555.         je    string_found
  556. finds_11:
  557.         inc    bx
  558.         xor    al,al
  559.         cmp    [di-1],al
  560.         jne    finds_2
  561.         dec    di
  562. finds_2:
  563.         mov    cx,10            ;Scan to next zero
  564.         repne    scasb
  565.         cmp    byte ptr [di],0     ;See if second zero. If so
  566.         jne    finds_1         ;  end of list.
  567. finds_3:
  568.         mov    bx,13
  569.         stc                ;Indicate string not found
  570. findstr_exit:
  571.         pop    es
  572.         pop    cx
  573.         ret
  574. string_found:
  575.         cmp    bx,12            ;If past the BAT commands,
  576.         jb    findstr_3        ;  then it is an internal cmd.
  577.         mov    bx,12
  578. findstr_3:
  579.         clc                ;Set string found flag
  580.         jmp    short findstr_exit
  581. findstr     endp
  582.  
  583. ;-----------------------------------------------------------------------------
  584. ; CAPSALPHA capitalizes word pointed to by SI
  585. ; Entry:  SI - Pointer to ASCII word to capitalize
  586. ; Exit:   CX - Size of word
  587. ;-----------------------------------------------------------------------------
  588. capsalpha    proc near
  589.         assume    ds:nothing,es:nothing
  590.         push    ax
  591.         xor    ax,ax            ;Exit on non-alpha chars
  592.         jmp    short capsword_entry2
  593. capsalpha    endp
  594.  
  595. ;-----------------------------------------------------------------------------
  596. ; CAPSWORD capitalizes word pointed to by SI
  597. ; Entry:  SI - Pointer to ASCII word to capitalize
  598. ; Exit:   CX - Size of word
  599. ;-----------------------------------------------------------------------------
  600. capsword    proc near
  601.         assume    ds:nothing,es:nothing
  602.         push    ax
  603.         mov    ah,1            ;Ignore extra characters
  604. capsword_entry2:
  605.         push    di
  606.         push    si
  607.         push    es
  608.         push    ds            ;Set ES:DI = DS:SI
  609.         pop    es
  610.         mov    di,si
  611.         xor    cx,cx            ;Clear byte counter.
  612. caps_1:
  613.         lodsb                ;Get character
  614.         cmp    al," "                  ;Allow any non-space character
  615.         jbe    caps_exit
  616.         call    capschar
  617.         jnc    caps_2
  618.         or    ah,ah
  619.         je    caps_exit
  620. caps_2:
  621.         stosb                ;Save character
  622.         inc    cx            ;Inc byte counter
  623.         jmp    short caps_1
  624. caps_exit:
  625.         pop    es
  626.         pop    si
  627.         pop    di
  628.         pop    ax
  629.         ret
  630. capsword    endp
  631.  
  632. ;-----------------------------------------------------------------------------
  633. ; CAPSCHAR capitalizes character in AL
  634. ; Entry:  AL - ASCII char to capitalize
  635. ; Exit:   CX - Size of word
  636. ;-----------------------------------------------------------------------------
  637. capschar    proc near
  638.         assume    ds:nothing,es:nothing
  639.  
  640.         cmp    al,"a"                  ;If between a and z,
  641.         jb    caps_char_2           ;  capitalize it.
  642.         cmp    al,"z"
  643.         ja    caps_char_exit
  644.         and    al,0DFh
  645. caps_char_1:
  646.         clc
  647.         jmp    short caps_char_exit
  648. caps_char_2:
  649.         cmp    al,'Z'
  650.         ja    caps_char_3
  651.         cmp    al,'A'
  652.         jae    caps_char_1
  653. caps_char_3:
  654.         stc
  655. caps_char_exit:
  656.         ret
  657. capschar    endp
  658.  
  659. ;-----------------------------------------------------------------------------
  660. ; REDIRECT CLOSE post process redirection commands
  661. ; Entry:  DI - Pointer to end of COM file data.
  662. ; Exit:   CF - Set if error.
  663. ;      Batch file line updated to remove any redirection symbols
  664. ;-----------------------------------------------------------------------------
  665. redirect_close    proc    near
  666.         assume    cs:code,ds:code
  667.         cmp    redirect_in,0        ;See if redirecton active
  668.         je    redirclose_1
  669.         mov    redirect_in,0
  670.         mov    bx,offset redirci_next    ;Append close redirect file
  671.         call    include_code        ;  routine to code.
  672.         xor    cx,cx
  673.         call    inline_code
  674. redirclose_1:
  675.         cmp    redirect_out,0        ;See if redirecton active
  676.         je    redirclose_2
  677.         mov    redirect_out,0
  678.         mov    bx,offset redirco_next    ;Append close redirect file
  679.         call    include_code        ;  routine to code.
  680.         xor    cx,cx
  681.         call    inline_code
  682. redirclose_2:
  683.         cmp    pipein_flag,0        ;See if in pipe curr active
  684.         je     redirclose_3
  685.         mov    dx,pipein_file        ;Get offset of input pipe file
  686.         mov    cx,1            ;Indicate parameter type
  687.         mov    bx,offset redirdel_next    ;Delete the piping file
  688.         call    include_code
  689.         call    inline_code
  690.         mov    pipein_flag,0        ;Clear flag
  691. redirclose_3:
  692.         cmp    pipeout_flag,0        ;See if out pipe curr active
  693.         je     redirclose_exit
  694.         mov    dx,pipeout_file        ;Get offset of input pipe file
  695.         xor    bx,bx            ;Add output redirection code
  696.         xor    ax,ax            ;  to file.
  697.         call    redirect_openi
  698.         mov    pipein_flag,1        ;Set pipe input flag
  699.         mov    pipeout_flag,0        ;Clear pipe output flag
  700.         mov    pipein_file,dx        ;Copy pointer to filename
  701. redirclose_exit:
  702.         ret
  703. redirect_close    endp
  704.  
  705. ;-----------------------------------------------------------------------------
  706. ; REDIRECT CHECK process redirection commands
  707. ; Entry:  SI - Pointer to current BAT file line
  708. ;      DI - Pointer to end of COM file data.
  709. ; Exit:   CF - Set if error.
  710. ;      Source file line updated to remove any redirection symbols
  711. ;-----------------------------------------------------------------------------
  712. redirect_check    proc    near
  713.         assume    cs:code,ds:code
  714.         push    si
  715.         call    redirect_close
  716.         mov    quote_flag,0
  717. redirect_1:
  718.         mov    bp,si            ;Save current position
  719.         lodsb
  720.         cmp    al,'"'                  ;See if quote
  721.         jne    redirect_2
  722.         not    quote_flag
  723. redirect_2:
  724.         cmp    quote_flag,0        ;Ignore characters in quotes
  725.         jne    redirect_1
  726. ;
  727. ; Check for piping
  728. ;
  729.         cmp    al,'|'                  ;Check for piping symbol
  730.         jne    redirect_5
  731.         mov    byte ptr [si-1],13    ;Replace | with CR
  732.  
  733.         mov    bx,offset pipe1_file    ;Get offset of pipe file to
  734.         cmp    pipe_toggle,0        ;  use.  Alternate files so
  735.         jne    redirect_3         ;  that input and output files
  736.         mov    bx,offset pipe2_file    ;  don't get mixed up.
  737. redirect_3:
  738.         not    pipe_toggle
  739.         xor    dx,dx            ;If file not already used,
  740.         or     dx,[bx]            ;  load the filename into
  741.         jne    redirect_4         ;  the COM data buffer.
  742.         mov    dx,di
  743.         sub    dx,databuff_start    ;Compute offset of filename
  744.         mov    [bx],dx            ;Save pointer to filename
  745.         lea    si,[bx+2]        ;Get address of filename
  746.         mov    ah,1
  747.         call    copy_string        ;Copy name to COM data buffer
  748.         xor    al,al            ;Terminate filename with zero
  749.         stosb
  750. redirect_4:
  751.         mov    pipeout_file,dx
  752.         mov    pipeout_flag,1
  753.         xor    bx,bx            ;Add output redirection code
  754.         xor    ax,ax            ;  to file.
  755.         call    redirect_openo
  756.         jmp    short redirect_exit    ;Terminate line scan.
  757. ;
  758. ; Check for output redirection
  759. ;
  760. redirect_5:
  761.         cmp    al,'>'                  ;Check for redirect out
  762.         jne    redirect_7
  763.         xor    bx,bx
  764.         cmp    byte ptr [si],'>'       ;Check for append redirect
  765.         jne    redirect_6
  766.         lodsb                ;Remove 2nd >
  767.         inc    bx            ;Set append flag
  768. redirect_6:
  769.         push    bx            ;Save append flag
  770.         xor    bl,bl
  771.         call    scan4char        ;Get filename
  772.         mov    dx,di
  773.         mov    ah,1            ;Copy only one word
  774.         call    copy_string
  775.         xor    al,al            ;Terminate name with zero
  776.         stosb
  777.         sub    dx,databuff_start    ;Compute offset of filename
  778.         pop    ax            ;Get append flag
  779.         call    redirect_openo
  780.         call    erase_redirect        ;Erase redirect from line.
  781.         jmp    short redirect_1
  782. redirect_7:
  783.         cmp    al,'<'                  ;Check for redirect in
  784.         jne    redirect_10
  785.         xor    bl,bl
  786.         call    scan4char        ;Get filename
  787.         mov    dx,di
  788.         mov    ah,1            ;Copy only one word
  789.         call    copy_string
  790.         xor    al,al            ;Terminate name with zero
  791.         stosb
  792.  
  793.         sub    dx,databuff_start    ;Compute offset of filename
  794.         call    redirect_openi
  795.         call    erase_redirect        ;Erase redirect from line.
  796.         jmp    redirect_1
  797. redirect_10:
  798.         cmp    al,13
  799.         je    redirect_exit
  800.         jmp    redirect_1
  801. redirect_exit:
  802.         clc
  803.         pop    si
  804.         ret
  805. redirect_check    endp
  806.  
  807. ;-----------------------------------------------------------------------------
  808. ; REDIRECT OPENO process redirection commands
  809. ; Entry:  AX - 1 = append file.
  810. ; Entry:  DX - Offset from data buffer start of file name
  811. ;      BX - 0 no translation of filename.
  812. ;-----------------------------------------------------------------------------
  813. redirect_openo    proc    near
  814.         assume    cs:code,ds:code
  815.         push    si
  816.         push    ax            ;Save append flag
  817.         mov    cx,0031h        ;Indicate parameter type
  818.         or    bx,bx            ;See if env var or cmd line
  819.         je    redirect_oo1        ;  parms.
  820.  
  821.         mov    bx,offset procstr_next    ;Get offset of translate
  822.         call    include_code        ;  routine. Include if needed.
  823.  
  824.         push    bx
  825.         mov    bx,offset prse_buff_ptr - offset data_start
  826.         mov    cx,0021h        ;Indicate parameter type
  827.         call    inline_code        ;Insert translate code.
  828.         mov    dx,bx
  829.         pop    bx
  830.         mov    cx,32h
  831. redirect_oo1:
  832.         mov    bx,offset rediroo_next    ;Append open redirect file
  833.         call    include_code
  834.         pop    bx            ;Restore append flag
  835.         call    inline_code
  836.         mov    redirect_out,1        ;Set redirect active flag
  837.         pop    si
  838.         ret
  839. redirect_openo    endp
  840.  
  841. ;-----------------------------------------------------------------------------
  842. ; REDIRECT OPENI loads code to open a file for input redirection
  843. ; Entry:  DX - Offset from data buffer start of file name
  844. ;      BX - 0 no translation of filename.
  845. ;-----------------------------------------------------------------------------
  846. redirect_openi    proc    near
  847.         assume    cs:code,ds:code
  848.         push    si
  849.         mov    cx,1            ;Indicate parameter type
  850.         or    bx,bx            ;See if env var or cmd line
  851.         je    redirect_oi1        ;  parms.
  852.  
  853.         mov    bx,offset procstr_next    ;Get offset of translate
  854.         call    include_code        ;  routine. Include if needed.
  855.  
  856.         mov    bx,offset prse_buff_ptr - offset data_start
  857.         mov    cx,21h            ;Indicate parameter type
  858.         call    inline_code        ;Insert translate code.
  859.         mov    dx,bx
  860.         mov    cx,2
  861. redirect_oi1:
  862.         mov    bx,offset rediroi_next    ;Append open redirect file
  863.         call    include_code
  864.         call    inline_code
  865.         mov    redirect_in,1        ;Set redirect active flag
  866.         pop    si
  867.         ret
  868. redirect_openi    endp
  869.  
  870. ;-----------------------------------------------------------------------------
  871. ; ERASE REDIRECT
  872. ; Entry:  BP - Pointer to redirect character
  873. ;      SI - Pointer to end of redirect phrase.
  874. ;-----------------------------------------------------------------------------
  875. erase_redirect    proc    near
  876.         assume    cs:code,ds:code
  877.         push    di            ;Save ptr to data buffer
  878.         mov    al,' '
  879.         mov    di,bp            ;Get start of redirect string
  880.         dec    si
  881. erase_1:
  882.         stosb
  883.         cmp    di,si
  884.         jb    erase_1
  885.         pop    di
  886.         ret
  887. erase_redirect    endp
  888.  
  889. ;-----------------------------------------------------------------------------
  890. ; IF CMD compiles an IF command.
  891. ; Entry:  SI - Pointer to character after the IF command
  892. ;      DI - Pointer to end of compiled data.
  893. ; Exit:   AL - Error code if CF set
  894. ;      CF - Set if error
  895. ;      SI,DI updated.
  896. ;-----------------------------------------------------------------------------
  897. if_cmd        proc    near
  898.         assume    cs:code,ds:code
  899.         xor    bl,bl            ;Find 1st char of next word
  900.         call    scan4char
  901.         mov    cx,si            ;Save pointer to test
  902.         mov    dx,di
  903.         mov    bp,0            ;Clear 'NOT' flag
  904. ;
  905. ;See if NOT prefix is used in test
  906. ;
  907.         lodsw                ;Get 1st two chars of test
  908.         or    ax,2020h
  909.         cmp    ax,'on'                 ;See if 'no'
  910.         jne    if_cmd_chk_cmp
  911.         lodsw                ;Get 2nd and 3rd characters
  912.         or    al,20h            ;Convert 3rd char to lower
  913.         cmp    al,'t'                  ;  case.   See if last char is
  914.         jne    if_cmd_chk_cmp         ;  't' followed by s space
  915.         cmp    ah,' '
  916.         ja    if_cmd_chk_cmp
  917.         inc    bp
  918.         xor    bl,bl            ;Find next word
  919.         call    scan4char
  920.         mov    cx,si
  921. ;
  922. ;Test for string compare by looking for == signs.
  923. ;
  924. if_cmd_chk_cmp:
  925.         mov    si,cx            ;Restore pointer to condition
  926.         mov    bl,3            ;Find next space or equal sign
  927.         call    scan4char
  928.         jc    if_syntax_jmp
  929.         xor    bl,bl
  930.         call    scan4char        ;Find next word
  931.         cmp    word ptr [si],"=="    ;See if string compare
  932.         je     if_cmd_cmp1        ;No, check other tests
  933.         jmp    if_cmd_chk_errlev
  934. if_cmd_cmp1:
  935.         inc    si            ;Move SI past equals signs
  936.         inc    si
  937.         xor    bl,bl            ;Find second string
  938.         call    scan4char
  939.         jnc    if_cmd_cmp2
  940. if_syntax_jmp:
  941.         jmp    short if_syntax
  942. if_cmd_cmp2:
  943.         push    si            ;Save pointer to 2nd string
  944.         mov    si,cx            ;Restore ptr to 1st string
  945.         push    di            ;Save ptr to size byte
  946.         inc    di
  947.         mov    dx,di            ;Save ptr to start of string
  948.         sub    dx,databuff_start
  949.         mov    ah,2            ;Copy only one word
  950.         call    copy_string        ;Load string into data space
  951.         xor    al,al
  952.         stosb
  953.         or    bx,bx            ;See if translation is needed
  954.         pop    bx            ;Restore pointer to size byte
  955.         mov    [bx],cl         ;Save length of string
  956.         mov    cl,1            ;Assume LEA parameter call
  957.         je    if_cmd_03
  958.  
  959.         mov    bx,offset procstr_next    ;Append translate string
  960.         call    include_code        ;  routine to code.
  961.         mov    bx,offset prs2_buff_ptr - offset data_start
  962.         mov    cx,0021h        ;Indicate parameter type
  963.         call    inline_code        ;Insert translate code.
  964.         mov    dx,bx            ;Copy ptr to buffer.
  965.         mov    cx,2            ;Use MOV parameter type
  966. if_cmd_03:
  967.         pop    si            ;Restore ptr to 2nd string
  968.         push    dx            ;Save pointer to 1st string
  969.         push    cx            ;Save parameter type
  970. if_cmd_04:
  971.         push    di            ;Save ptr to size byte
  972.         inc    di
  973.         mov    dx,di            ;Save ptr to start of string
  974.         sub    dx,databuff_start
  975.         mov    ah,2
  976.         call    copy_string        ;Load string into data space
  977.         xor    al,al
  978.         stosb
  979.         or    bx,bx            ;See if translation is needed
  980.         pop    bx
  981.         mov    [bx],cl         ;Save length of string
  982.         mov    cx,10h            ;Set parameter type
  983.         je    if_cmd_06
  984.  
  985.         mov    bx,offset procstr_next    ;Append translate string
  986.         call    include_code        ;  routine to code.
  987.         mov    bx,offset prse_buff_ptr - offset data_start
  988.         mov    cx,0021h        ;Indicate parameter type
  989.         call    inline_code        ;Insert translate code.
  990.         mov    dx,bx            ;Copy ptr to buffer.
  991.         mov    cx,20h            ;Use proper parameter type
  992. if_cmd_06:
  993.         mov    bx,offset ifequal_next    ;Append comparison code
  994.         call    include_code
  995.         pop    bx            ;Restore param 1 type
  996.         and    bl,0fh
  997.         or    cl,bl            ;Combine parameter types
  998.         mov    bx,dx            ;Move parameter 2
  999.         pop    dx            ;Restore parameter 1
  1000.         call    inline_code        ;Add call to string compare
  1001.         jmp    if_cmd_10
  1002. if_syntax:
  1003.         mov    dx,offset errmsg6    ;Syntax error.
  1004.         stc
  1005.         jmp    if_exit
  1006. ;
  1007. ;See if ERRORLEVEL test.
  1008. ;
  1009. if_cmd_chk_errlev:
  1010.         mov    si,cx            ;Restore pointer to 1st string
  1011.         mov     bx,cx            ;Save pointer to 1st string
  1012.         mov    di,offset ifstr1    ;See if ERRORLEVEL test
  1013.         call    capsalpha
  1014.         cmp    cx,10
  1015.         jne    if_cmd_2
  1016.         repe    cmpsb            ;Compare strings
  1017.         jne    if_cmd_2
  1018.         mov    bx,offset iferrlev_next ;Save offset of errlev code
  1019.         push    bx            ;  on stack.  Use exist code
  1020.          xor    bl,bl
  1021.         call    scan4char        ;Scan to next word.
  1022.         cmp    byte ptr [si],'='
  1023.         jne    if_cmd_21
  1024.         inc    si
  1025.          xor    bl,bl
  1026.         call    scan4char        ;Scan to next word.
  1027.         jmp    short if_cmd_21     ;  to append error code.
  1028. ;
  1029. ;See if EXIST test.
  1030. ;
  1031. if_cmd_2:
  1032.         mov    si,bx            ;Restore pointer to 1st string
  1033.         mov    di,offset ifstr2    ;See if EXIST test
  1034.         cmp    cx,5            ;Check length of string
  1035.         jne    if_syntax
  1036.         repe    cmpsb            ;Compare strings
  1037.         jne    if_syntax
  1038.         mov    bx,offset ifexist_next    ;Save test existance code off
  1039.         push    bx
  1040.          xor    bl,bl
  1041.         call    scan4char        ;Scan to next word.
  1042. if_cmd_21:
  1043.         mov    di,dx            ;Restore data pointer
  1044.         sub    dx,databuff_start
  1045.         mov    ah,2
  1046.         call    copy_string
  1047.         xor    al,al            ;Terminate string with zero.
  1048.         stosb
  1049.         mov    cl,21h            ;Set parameter type
  1050.         or    bx,bx            ;See if translation is needed
  1051.         je    if_cmd_3
  1052.  
  1053.         mov    bx,offset procstr_next    ;Append translate string
  1054.         call    include_code        ;  routine to code.
  1055.         mov    bx,offset prse_buff_ptr - offset data_start
  1056.         mov    cx,0021h        ;Indicate parameter type
  1057.         call    inline_code        ;Insert translate code.
  1058.         mov    dx,bx            ;Copy ptr to buffer.
  1059.         mov    cl,22h            ;Use proper parameter type
  1060. if_cmd_3:
  1061.         pop    bx            ;Restore test code offset
  1062.         call    include_code
  1063.         mov    bx,offset prs2_buff_ptr - offset data_start
  1064.         call    inline_code        ;Insert exist test call
  1065. if_cmd_10:
  1066.         mov    cx,200h         ;Include Jump if carry opcode
  1067.         or    bp,bp
  1068.         je    if_cmd_12
  1069.         mov    cx,300h         ;Change to Jump if not carry
  1070. if_cmd_12:
  1071.         call    inline_code
  1072.         push    ax            ;Save address of jmp to modify
  1073.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1074. ;
  1075. ;Compile the remainder of the line as if it were a normal statment.
  1076. ;
  1077.         xor    bl,bl            ;Scan for next word
  1078.         call    scan4char
  1079.         call    parse            ;Compile remainder of line.
  1080.  
  1081.         pop    cx            ;Compute the difference for the
  1082.         pop    bx            ;  jmp opcode.
  1083.         jc    if_exit         ;If error during parse, exit.
  1084.         push    es
  1085.         mov    ax,word ptr codebuff_ptr
  1086.         mov    es,word ptr codebuff_ptr[2]
  1087.         sub    ax,cx
  1088.         mov    es:[bx],ax        ;Save jmp offset
  1089.         pop    es
  1090.         clc
  1091. if_exit:
  1092.         ret
  1093. if_cmd        endp
  1094.  
  1095. ;-----------------------------------------------------------------------------
  1096. ; FOR CMD compiles an FOR command.
  1097. ; Entry:  SI - Pointer to character after the FOR command
  1098. ;      DI - Pointer to end of compiled data.
  1099. ; Exit:   AL - Error code if CF set
  1100. ;      CF - Set if error
  1101. ;      SI,DI updated.
  1102. ;-----------------------------------------------------------------------------
  1103. for_cmd     proc    near
  1104.         assume    cs:code,ds:code
  1105.         cmp    for_active_flag,0
  1106.         je    for_cmd_0
  1107.         mov    dx,offset errmsg11    ;No nested FOR loops
  1108.         stc
  1109.         jmp    for_exit
  1110. for_cmd_0:
  1111.         mov    goto_active,0        ;Clear goto detect flag
  1112.         inc    for_active_flag
  1113.         xor    bl,bl            ;Find 1st char of next word
  1114.         call    scan4char
  1115.         jc    jmp_for_syntax
  1116.         mov    bp,si            ;Save pointer to loop variable
  1117.         mov    dx,di
  1118.         sub    dx,word ptr databuff_start
  1119. ;
  1120. ;Copy the set data to the com file data area.  As always, if environment
  1121. ;variables or command line parameters are in the data, insert a call to
  1122. ;the translate routine before calling the for loop routine.
  1123. ;
  1124. for_cmd_1:
  1125.         lodsb                ;Scan until '(' is found
  1126.         cmp    al,13            ;  indicating the start of the
  1127.         jne    for_cmd_2        ;  data set.
  1128. jmp_for_syntax:
  1129.         jmp    for_syntax
  1130. for_cmd_2:
  1131.         cmp    al,'('
  1132.         jne    for_cmd_1
  1133.         mov    ah,3            ;Copy until ')' found.
  1134.         call    copy_string
  1135.         xor    al,al            ;Terminate string with zero.
  1136.         stosb
  1137.         mov    cx,11h
  1138.         or    bx,bx
  1139.         je    for_cmd_3
  1140.  
  1141.         mov    bx,offset procstr_next    ;Append translate string
  1142.         call    include_code        ;  routine to code.
  1143.         mov    bx,offset for_buff_ptr - offset data_start
  1144.         mov    cx,0021h        ;Indicate parameter type
  1145.         call    inline_code        ;Insert translate code.
  1146.         mov    dx,bx            ;Copy ptr to buffer.
  1147.         mov    cl,12h            ;Use proper parameter type
  1148. for_cmd_3:
  1149.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1150.         mov    bx,offset forloop_next
  1151.         call    include_code
  1152.         mov    bx,di            ;Initialize for loop data
  1153.         sub    bx,databuff_start    ;  structure.
  1154.         mov    word ptr [di],0
  1155.         inc    di
  1156.         inc    di
  1157.         call    inline_code        ;Insert call to loop code.
  1158.         mov    cx,200h         ;Include Jump if carry opcode
  1159.         call    inline_code
  1160.         push    ax            ;Save address of jmp to modify
  1161.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1162.  
  1163. ;
  1164. ;Scan the remainder of the line. Replace all instances of the loop variable
  1165. ;with a special code that the run time translate routine understands.
  1166. ;
  1167.         xor    bl,bl            ;Find DO
  1168.         call    scan4char
  1169.         jc    for_syntax_1
  1170.         push    si
  1171.         lodsw                ;Confirm DO exists
  1172.         and    ax,0dfdfh        ;Convert to upper case
  1173.         cmp    ax,"OD"
  1174.         pop    si
  1175.         jne    for_syntax_1
  1176.         mov    bl,1            ;Find end of 'DO'
  1177.         call    scan4char
  1178.         jc    for_syntax_1
  1179.         xor    bl,bl            ;Find start of loop command.
  1180.         call    scan4char
  1181.         jc    for_syntax_1
  1182.         push    si            ;Save pointer to command.
  1183.         push    di            ;Save data buffer pointer.
  1184.         mov    di,si
  1185.         mov    bl,2            ;Find the end of the line.
  1186.         call    scan4char
  1187.         mov    dx,si            ;Save pointer to end of line
  1188. for_cmd_4:
  1189.         mov    si,bp            ;Get ptr to loop variable.
  1190.         mov    cx,3            ;Scan the remainder of the
  1191.         repe    cmpsb            ;  line for the loop variable.
  1192.         jne    for_cmd_5        ;  When found, replace with
  1193.         dec    di            ;  % followed by 7f7fh. This
  1194.         dec    di            ;  flag tells the runtime
  1195.         mov    ax,7f7fh        ;  xlate routine to sub in
  1196.         stosw                ;  the loop string.
  1197. for_cmd_5:
  1198.         cmp    di,dx            ;See if at the end of the line.
  1199.         jb    for_cmd_4
  1200.         pop    di            ;Restore data buffer ptr
  1201.         pop    si            ;Restore ptr to command.
  1202. ;
  1203. ;Compile the remainder of the line as if it were a normal statment.
  1204. ;
  1205.         call    parse            ;Compile remainder of line.
  1206.  
  1207.         pop    cx            ;Get code ptr after loop code
  1208.         pop    bx            ;Get addr of JC
  1209.         pop    ax            ;Get code ptr to loop code
  1210.         jc    for_exit1
  1211.         mov    dx,cx            ;DX may have had an error msg
  1212.  
  1213.         sub    ax,word ptr codebuff_ptr ;Compute displacment from END
  1214.         sub    ax,3             ;  of JMP opcode.
  1215.         mov    cx,400h         ;Insert JMP opcode after code
  1216.         call    inline_code        ;  for statments inside FOR
  1217.         mov    ax,word ptr codebuff_ptr;  loop.
  1218.         sub    ax,dx
  1219.         push    es
  1220.         mov    es,word ptr codebuff_ptr[2]
  1221.         mov    es:[bx],ax
  1222.         pop    es
  1223. ;
  1224. ; If goto parsed during FOR, place jump for goto after FOR loop
  1225. ;
  1226.         cmp    goto_active,0
  1227.         je     for_exit
  1228.         mov    dx,goto_data_ptr
  1229.         mov    bx,offset gotodly_next    ;Append goto delay
  1230.         call    include_code        ;  routine to code.
  1231.         mov    cx,1
  1232.         call    inline_code        ;Add code to COM file.
  1233. for_exit:
  1234.         clc
  1235. for_exit1:
  1236.         mov    for_active_flag,0    ;Clear flag
  1237.         ret
  1238. for_syntax_1:
  1239.         add    sp,6            ;Clean off stack
  1240. for_syntax:
  1241.         mov    dx,offset errmsg6    ;Syntax error
  1242.         stc
  1243.         jmp    short for_exit1
  1244. for_cmd     endp
  1245.  
  1246. ;-----------------------------------------------------------------------------
  1247. ; GOTO CMD compiles a goto command.
  1248. ; Entry:  SI - Pointer to first character after the command.
  1249. ;      DI - Pointer to end of compiled data.
  1250. ; Exit:   AL - Error code if CF set
  1251. ;      CF - Set if error
  1252. ;      SI,DI updated.
  1253. ;-----------------------------------------------------------------------------
  1254. goto_cmd    proc    near
  1255.         assume    cs:code,ds:code
  1256.         mov    goto_active,1        ;Needed for FOR loop
  1257.         mov    bp,di            ;Save ptr to start of string.
  1258.         xor    bl,bl            ;Find the first nonspace char.
  1259.         call    scan4char
  1260.         mov    dx,offset errmsg6    ;Check for Syntax error
  1261.         jc    goto_cmd_error
  1262.         cmp    byte ptr [si],':'    ;See if leading :.  If so,
  1263.         jne    goto_c0            ;  don't include in label.
  1264.         inc    si
  1265. goto_c0:
  1266.         push    si
  1267.         xor    ax,ax
  1268.         stosw                ;Save word in case FOR loop
  1269.         xor    ah,ah            ;  delay goto.
  1270.         call    copy_string        ;Copy label to COM data.
  1271.         xor    al,al            ;Terminate label with zero
  1272.         stosb
  1273.         pop    si
  1274.         mov    dx,offset errmsg8    ;Check to see if label found.
  1275.         or    cx,cx            ;If not, error.
  1276.         je    goto_cmd_error
  1277.         cmp    for_active_flag,0    ;If in for loop, force eval
  1278.         jne    goto_c1            ;  Jmp must occur after FOR
  1279.  
  1280.         or    bx,bx            ;See if env var or cmd line
  1281.         je    goto_c2         ;  parms.  If not hard code jmp
  1282. goto_c1:
  1283.         mov    bx,offset procstr_next    ;Get offset of translate
  1284.         call    include_code        ;  routine. Include if needed.
  1285.  
  1286.         mov    dx,bp            ;Get pointer to label.
  1287.         sub    dx,databuff_start    ;Compute offset.
  1288.         mov    goto_data_ptr,dx    ;Save offset in case FOR loop
  1289.         add    dx,2            ;Move past word ptr
  1290.         mov    bx,offset prse_buff_ptr - offset data_start
  1291.         mov    cx,0021h        ;Indicate parameter type
  1292.         call    inline_code        ;Insert translate code.
  1293.         mov    dx,bx
  1294.         mov    cx,32h            ;Use proper parameter type
  1295.         mov    bx,offset goto_next    ;Append goto string
  1296.         call    include_code        ;  routine to code.
  1297.         xor    bx,bx
  1298.         cmp    for_active_flag,0    ;If in FOR loop delay goto.
  1299.         je    goto_c11        ;  Pass ptr to word to save
  1300.         mov    bx,goto_data_ptr    ;  destination address.
  1301. goto_c11:
  1302.         call    inline_code        ;Add code to COM file.
  1303.         jmp    goto_cmd_exit
  1304. ;
  1305. ;Since label doesn't use env vars or cmd line params, hard code JMP.
  1306. ;
  1307. goto_c2:
  1308.         mov    di,bp            ;Reset data ptr to ignore label
  1309.         call    getlabel        ;See if label in list.
  1310.         mov    ax,bx            ;Copy pointer to label pointer
  1311.         add    ax,2            ;  to code.
  1312.         sub    ax,databuff_start    ;Compute offset of pointer
  1313.         mov    cx,100h         ;Insert JMP opcode.
  1314.         call    inline_code
  1315. goto_cmd_exit:
  1316.         mov    bl,2
  1317.         call    scan4char        ;Scan to the end of the line.
  1318.         clc
  1319. goto_cmd_exit1: ret
  1320. goto_cmd_error:
  1321.         stc
  1322.         jmp    short goto_cmd_exit1
  1323. goto_cmd       endp
  1324.  
  1325. ;-----------------------------------------------------------------------------
  1326. ; LABEL CMD processes a label found in the bat file.
  1327. ; Entry:  SI - Pointer to first character of the label
  1328. ;      DI - Pointer to end of compiled data.
  1329. ; Exit:   AL - Error code if CF set
  1330. ;      CF - Set if error
  1331. ;      SI,DI updated.
  1332. ;-----------------------------------------------------------------------------
  1333. label_cmd    proc    near
  1334.         assume    cs:code,ds:code
  1335.         inc    si            ;Move past ':'
  1336.         call    getlabel
  1337.         cmp    word ptr [bx+2],-1    ;See if list entry initialized
  1338.         jne    label_error        ;  if so error.
  1339.         mov    ax,word ptr codebuff_ptr
  1340.         mov    [bx+2],ax        ;Save code ptr in COM data
  1341.         mov    bl,2
  1342.         call    scan4char        ;Scan to the end of the line.
  1343.         clc
  1344. label_exit:
  1345.         ret
  1346. label_error:
  1347.         mov    dx,offset errmsg8    ;Two identical labels
  1348.         stc
  1349.         jmp    short label_exit
  1350. label_cmd    endp
  1351.  
  1352. ;-----------------------------------------------------------------------------
  1353. ; GETLABEL searches the label list in the data area.  If a matching label entry
  1354. ;   is found it is returned, if not a label entry is created.
  1355. ; Entry:  SI - Pointer to first character of the label
  1356. ;      DI - Pointer to end of compiled data.
  1357. ; Exit:   BX - Points to label entry.
  1358. ;      SI,DI updated.
  1359. ;-----------------------------------------------------------------------------
  1360. getlabel    proc    near
  1361.         assume    cs:code,ds:code
  1362.         call    capsword        ;Convert to caps & get length.
  1363.         cmp    cx,8            ;Max length of a label 8
  1364.         jbe    getlabel_1        ;  characters to be consistant
  1365.         mov    cx,8            ;  with DOS.
  1366. getlabel_1:
  1367.         mov    bp,di            ;Save data ptr
  1368.         mov    di,offset firstlabel    ;Get ptr to the 1st label
  1369.         mov    bx,di
  1370.         cmp    word ptr [di],-1    ;See if any labels defined.
  1371.         je    getlabel_2        ;No, skip label list search.
  1372.  
  1373.         push    cx            ;Save label size
  1374.         add    bx,[bx]         ;Point to first label
  1375.         call    lblsrch_code        ;Search label list.
  1376.         pop    cx
  1377.         mov    di,bp            ;Create label entry.
  1378.         jnc    getlabel_exit
  1379. getlabel_2:
  1380.         mov    di,bp            ;Create label entry.
  1381.         mov    ax,-1
  1382.         stosw                ;Clear end of list tag
  1383.         stosw                ;Indicate unitialized label
  1384.         mov    al,cl
  1385.         stosb                ;Save length of label
  1386.         rep    movsb            ;Copy label into data buffer
  1387.         mov    ax,bp
  1388.         sub    ax,bx            ;Compute offset to new label
  1389.         mov    [bx],ax         ;Load offset in prev. label
  1390.         mov    bx,bp            ;Get start of label entry
  1391. getlabel_exit:
  1392.         clc
  1393.         ret
  1394. getlabel    endp
  1395.  
  1396. ;-----------------------------------------------------------------------------
  1397. ; EXTERNAL CMD compiles a routine to exexute a program.
  1398. ; Entry:  SI - Pointer to character after the command
  1399. ;      DI - Pointer to end of compiled data.
  1400. ; Exit:   AL - Error code if CF set
  1401. ;      CF - Set if error
  1402. ;      SI,DI updated.
  1403. ;-----------------------------------------------------------------------------
  1404. external_cmd    proc    near
  1405.         assume    cs:code,ds:code
  1406.         mov    dx,di            ;Save ptr to filename
  1407.         sub    dx,databuff_start    ;Compute offset.
  1408.         mov    ah,1
  1409.         call    copy_string        ;Copy filename to COM data.
  1410.         mov    temp1,bx        ;Save translate flag
  1411.         dec    si            ;Back up one char
  1412.         xor    al,al            ;Terminate filename with zero
  1413.         stosb
  1414.         inc    di
  1415.         push    di            ;Save ptr to command line tail
  1416.         xor    ah,ah
  1417.         call    copy_string        ;Copy command line tail.
  1418.         mov    ax,000dh        ;Append CR and zero
  1419.         stosw
  1420.         pop    bp            ;Save length of cmd line tail.
  1421.         inc    cl            ;  Adjust for the CR since
  1422.         mov    [bp-1],cl        ;  ProcStr will add CR to the
  1423.         sub    bp,databuff_start    ;  count.  Exec prog fixes
  1424.         mov    cx,11h            ;  this at run time.
  1425.         or    bx,bx            ;See if translation code needed
  1426.         je    externalcmd_1
  1427. ;
  1428. ;See if we need translation for command line tail.
  1429. ;
  1430.         push    dx
  1431.         mov    dx,bp            ;Get pointer to cmd line tail
  1432.         mov    bx,offset procstr_next    ;Get offset of translate
  1433.         call    include_code        ;  routine.
  1434.         mov    bx,offset prse_buff_ptr - offset data_start
  1435.         mov    cx,21h            ;Indicate parameter type
  1436.         call    inline_code        ;Insert translate code.
  1437.         mov    cx,21h            ;Use proper parameter type
  1438.         mov    bp,bx
  1439.         pop    dx
  1440. externalcmd_1:
  1441. ;
  1442. ;See if we need translation for param.
  1443. ;
  1444.         mov    ax,temp1        ;Get translate flag for cmd
  1445.         or    ax,ax            ;See if extern cmd needs
  1446.         je    externalcmd_2        ;  translation.
  1447.         mov    bx,offset procstr_next    ;Get offset of translate
  1448.         call    include_code        ;  routine.
  1449.         mov    bx,offset prs2_buff_ptr - offset data_start
  1450.         push    cx
  1451.         mov    cx,21h            ;Indicate parameter type
  1452.         call    inline_code        ;Insert translate code.
  1453.         pop    cx
  1454.         and    cl,0f0h            ;Use proper parameter type
  1455.         or    cl,02h            ;  retain the prev param type
  1456.         mov    dx,bx            ;  for cmd line tail.
  1457. externalcmd_2:
  1458.         mov    bx,offset external_next ;Append prog launch code
  1459.         call    include_code
  1460.         mov    bx,bp            ;Get ptr to filename
  1461.         call    inline_code        ;Add code to COM file.
  1462.         clc
  1463.         ret
  1464. external_cmd    endp
  1465.  
  1466. ;-----------------------------------------------------------------------------
  1467. ; INTERNAL CMD compiles a command internal to command.com
  1468. ; Entry:  SI - Pointer to character after the command
  1469. ;      DI - Pointer to end of compiled data.
  1470. ; Exit:   AL - Error code if CF set
  1471. ;      CF - Set if error
  1472. ;      SI,DI updated.
  1473. ;-----------------------------------------------------------------------------
  1474. internal_cmd    proc    near
  1475.         assume    cs:code,ds:code
  1476.         inc    di            ;Make room for string size.
  1477.         push    di            ;Save ptr to internal command.
  1478.         push    si
  1479.         mov    si,offset internal_cmdsw
  1480.         movsw                ;Copy /C switch to tell
  1481.         movsb                ;  COMMAND.COM to execute and
  1482.         pop    si            ;  terminate.
  1483.         xor    ah,ah
  1484.         call    copy_string        ;Copy internal command
  1485.         mov    ax,000dh        ;Append CR and zero
  1486.         stosw
  1487.         pop    bp
  1488.         add    cl,3            ;Add length of /c switch
  1489.         mov    [bp-1],cl        ;Save length of command line
  1490.  
  1491.         mov    dx,bp            ;Get pointer to internal cmd
  1492.         sub    dx,databuff_start    ;Compute offset.
  1493.         mov    cx,1
  1494.         or    bx,bx            ;See if translation code needed
  1495.         je    internalcmd_1
  1496.  
  1497.         mov    bx,offset procstr_next    ;Get offset of translate
  1498.         call    include_code        ;  routine.
  1499.         mov    bx,offset prse_buff_ptr - offset data_start
  1500.         mov    cx,0021h        ;Indicate parameter type
  1501.         call    inline_code        ;Insert translate code.
  1502.         mov    cx,2            ;Use proper parameter type
  1503.         mov    dx,bx            ;Get input from str1 buffer
  1504. internalcmd_1:
  1505.         mov    bx,offset intcmd_next    ;Append internal cmd routine
  1506.         call    include_code        ;  to code.
  1507.         call    inline_code        ;Add code to COM file.
  1508.         clc
  1509.         ret
  1510. internal_cmd    endp
  1511.  
  1512. ;-----------------------------------------------------------------------------
  1513. ; PATH CMD compiles a path command
  1514. ; Entry:  Same as SET command
  1515. ;-----------------------------------------------------------------------------
  1516. path_cmd     proc    near
  1517.         assume    cs:code,ds:code
  1518.         mov    bp,2
  1519.         push    si
  1520.         add    si,4            ;Move past path cmd
  1521.         xor    bx,bx            ;Find the first nonspace char.
  1522.         call    scan4char        ;If no characters, set flag
  1523.         pop    si
  1524.         jnc    set_entry1        ;  to print path string.
  1525.         mov    bp,3
  1526.         jmp    short set_entry1
  1527. path_cmd     endp
  1528.  
  1529. ;-----------------------------------------------------------------------------
  1530. ; PROMPT CMD compiles a path command
  1531. ; Entry:  Same as SET command
  1532. ;-----------------------------------------------------------------------------
  1533. prompt_cmd     proc    near
  1534.         assume    cs:code,ds:code
  1535.         mov    bp,1
  1536.         jmp    short set_entry1
  1537. prompt_cmd     endp
  1538.  
  1539. ;-----------------------------------------------------------------------------
  1540. ; SET CMD compiles a command to change variables in the environment
  1541. ; Entry:  SI - Pointer to character after the command
  1542. ;      DI - Pointer to end of compiled data.
  1543. ; Exit:   CF - Set if error
  1544. ;      DX - Offset to error message if CF set.
  1545. ;      SI,DI updated.
  1546. ;-----------------------------------------------------------------------------
  1547. set_cmd     proc    near
  1548.         assume    cs:code,ds:code
  1549.         mov    bp,0            ;Assume not PATH or PROMPT
  1550. set_entry1:
  1551.         push    bp
  1552.         xor    bx,bx            ;Find the first nonspace char.
  1553.         call    scan4char
  1554.         mov    dx,di            ;Save ptr to set command.
  1555.         jc    setcmd_0
  1556.         xor    ah,ah
  1557.         call    copy_string        ;Copy string to COM data
  1558. setcmd_0:
  1559.         xor    al,al            ;Append zero
  1560.         stosb
  1561.         sub    dx,databuff_start    ;Compute offset of data.
  1562.         mov    cx,31h
  1563.         or    bx,bx            ;See if translation code needed
  1564.         je    setcmd_1
  1565.  
  1566.         mov    bx,offset procstr_next    ;Get offset of translate
  1567.         call    include_code        ;  routine.
  1568.         mov    bx,offset prse_buff_ptr - offset data_start
  1569.         mov    cx,21h            ;Indicate parameter type
  1570.         call    inline_code        ;Insert translate code.
  1571.         mov    cx,32h            ;Use proper parameter type
  1572.         mov    dx,bx            ;Get input from str1 buffer
  1573. setcmd_1:
  1574.         mov    bx,offset setenv_next    ;Append set routine to code.
  1575.         call    include_code
  1576.         pop    bx            ;Get PATH/PROMPT flag
  1577.         call    inline_code        ;Add code to COM file.
  1578.         clc
  1579.         ret
  1580. set_cmd     endp
  1581.  
  1582. ;-----------------------------------------------------------------------------
  1583. ; ECHO CMD compiles an ECHO command.
  1584. ; Entry:  SI - Pointer to character after the ECHO command
  1585. ;      DI - Pointer to end of compiled data.
  1586. ; Exit:   AL - Error code if CF set
  1587. ;      CF - Set if error
  1588. ;      SI,DI updated.
  1589. ;-----------------------------------------------------------------------------
  1590. echo_cmd    proc    near
  1591.         assume    cs:code,ds:code
  1592.         mov    dx,si            ;Save pointer to string start
  1593.         inc    dx            ;Move pointer past 1st space
  1594.         xor    bl,bl            ;Echo can either echo a
  1595.         call    scan4char        ;  string to the keyboard or
  1596.         jc    echo_c01        ;  toggle the echo flag.
  1597.         or    al,20h            ;Check for on or off keyword
  1598.         cmp    al,"o"                  ;  to indicate what type of
  1599.         jne    echo_c0         ;  Echo this is.
  1600.         mov    ax,[si+1]        ;Get next two characters
  1601.         or    al,20h            ;Make lower case
  1602.         mov    bl,1
  1603.         cmp    al,"n"                  ;Check for echo on
  1604.         je    echo_c00
  1605.         or    ah,20h            ;Make lower case
  1606.         cmp    ax,"ff"                 ;Check for echo off
  1607.         jne    echo_c0
  1608.         dec    bl
  1609.         mov    ah,[si+3]        ;Get character past word
  1610. echo_c00:
  1611.         cmp    ah," "                  ;Make sure not just the start
  1612.         ja    echo_c0         ;  of another word.
  1613.         mov    bl,2
  1614.         call    scan4char        ;Find end of line.
  1615.         jmp    short echo_exit
  1616. ;
  1617. ;Echo ASCII line, Include code in COM file to echo string.
  1618. ;
  1619. echo_c01:
  1620.         mov    si,dx            ;Restore data pointer
  1621.         cmp    byte ptr [si-2],'.'    ;See if Echo.
  1622.         jne    echo_exit
  1623.         mov    dx,di
  1624.         jmp    short echo_c1
  1625. echo_c0:
  1626.         mov    si,dx            ;Restore data pointer
  1627.         mov    dx,di
  1628.         xor    ah,ah
  1629.         call    copy_string        ;Copy string to COM data.
  1630. echo_c1:
  1631.         mov    ax,0a0dh        ;Terminate line with CRLF
  1632.         stosw
  1633.         xor    al,al            ;Append zero byte
  1634.         stosb
  1635.         mov    cx,1            ;Append runtime routines.
  1636.         sub    dx,databuff_start
  1637.         or    bx,bx            ;Check translate flag, if set
  1638.         je    echo_c21        ;  append translate code 1st.
  1639.         mov    bx,offset procstr_next    ;Append translate string
  1640.         call    include_code        ;  routine to code.
  1641.         mov    bx,offset prse_buff_ptr - offset data_start
  1642.         mov    cx,0021h        ;Indicate parameter type
  1643.         call    inline_code        ;Insert translate code.
  1644.         mov    dx,bx
  1645.         mov    cx,2            ;Use proper parameter type
  1646. echo_c21:
  1647.         mov    bx,offset echo_msg_next ;Append echo string
  1648.         call    include_code        ;  routine to code.
  1649. echo_c3:
  1650.         call    inline_code        ;Add code to COM file.
  1651. echo_cstatus:
  1652. echo_exit:
  1653.         clc
  1654. echo_cmd_exit:
  1655.         ret
  1656. echo_cmd    endp
  1657.  
  1658. ;-----------------------------------------------------------------------------
  1659. ; PAUSE CMD compiles a PAUSE command.
  1660. ; Entry:  SI - Pointer to character after the PAUSE command
  1661. ;      DI - Pointer to end of compiled data.
  1662. ; Exit:   AL - Error code if CF set
  1663. ;      CF - Set if error
  1664. ;      SI,DI updated.
  1665. ;-----------------------------------------------------------------------------
  1666. pause_cmd    proc    near
  1667.         assume    cs:code,ds:code
  1668. ;Append routine if necessary
  1669.         mov    bx,offset pause_next     ;Append PAUSE routine if
  1670.         call    include_code         ;  necessary.
  1671.  
  1672.         mov    cx,0            ;Add inline code with 0 params
  1673.         call    inline_code        ;  to call pause routine.
  1674.  
  1675.         mov    bl,2            ;Scan to end of line
  1676.         call    scan4char
  1677.         clc
  1678. pause_cmd_exit:
  1679.         ret
  1680. pause_cmd    endp
  1681.  
  1682. ;-----------------------------------------------------------------------------
  1683. ; SHIFT CMD compiles a SHIFT command.
  1684. ; Entry:  SI - Pointer to character after the SHIFT command
  1685. ;      DI - Pointer to end of compiled data.
  1686. ; Exit:   AL - Error code if CF set
  1687. ;      CF - Set if error
  1688. ;      SI,DI updated.
  1689. ;-----------------------------------------------------------------------------
  1690. shift_cmd    proc    near
  1691.         assume    cs:code,ds:code
  1692.         mov    bx,offset shift_next     ;Append shift routine if
  1693.         call    include_code         ;  necessary.
  1694.         mov    cx,0            ;Add inline code with 0 params
  1695.         call    inline_code        ;  to call pause routine.
  1696.         mov    bl,2            ;Scan to end of line
  1697.         call    scan4char
  1698.         clc
  1699.         ret
  1700. shift_cmd    endp
  1701.  
  1702. ;-----------------------------------------------------------------------------
  1703. ; REM CMD  Processes remark lines in batch file.
  1704. ; Entry:  SI - pointer to line in BAT file
  1705. ;-----------------------------------------------------------------------------
  1706. rem_cmd     proc near
  1707.         assume    cs:code,ds:code
  1708.         dec    si            ;Back up to make sure we don't
  1709. rem_c1:     lodsb                ;  miss a carrage return.
  1710.         cmp    al,1ah            ;Loop until end of line or end
  1711.         je    rem_exit        ;  of file.
  1712.         cmp    al,13
  1713.         jne    rem_c1
  1714. rem_exit:
  1715.         clc
  1716.         ret
  1717. rem_cmd     endp
  1718.  
  1719. ;-----------------------------------------------------------------------------
  1720. ; COPY STRING copies a string to the com file data buffer.
  1721. ; Entry:  SI - Pointer to 1st character of the string.
  1722. ;      DI - Pointer to end of compiled data.
  1723. ;      AH - 0 = copy until end of line
  1724. ;           1 = copy only one word
  1725. ;           2 = copy only one word, break on /
  1726. ;           3 = copy until ')'
  1727. ; Exit:   BX - 0 if no environment variables or command line parameters.
  1728. ;      CX - Size of string.
  1729. ;      SI,DI updated.
  1730. ;-----------------------------------------------------------------------------
  1731. copy_string    proc    near
  1732.         assume    cs:code,ds:code
  1733.         push    dx
  1734.         mov    dx,di            ;Copy pointer to string
  1735.         xor    bx,bx            ;Clear param/env flag
  1736.         xor    cx,cx            ;Clear count
  1737. copystr_1:
  1738.         lodsb                ;Get byte
  1739.         cmp    al,13            ;See if carrage return
  1740.         je    copystr_exit        ;Yes, quit.
  1741.         cmp    al,1ah            ;See if EOF
  1742.         je    copystr_exit
  1743. copystr_2:
  1744.         cmp    ah,3            ;See if set copy
  1745.         jne    copystr_3        ;No, skip next test.
  1746.         cmp    al,')'                  ;See if end of set
  1747.         je    copystr_exit        ;Yes, quit.
  1748.         jmp    short copystr_4
  1749. copystr_3:
  1750.         or     ah,ah            ;See if phrase or word copy
  1751.         je     copystr_4        ;Phase, skip next test.
  1752.         cmp    al,' '                  ;See if end of word.
  1753.         jbe    copystr_exit        ;Yes, quit.
  1754.         cmp    al,'='                  ;Equal sign indicates end of
  1755.         je    copystr_exit        ;  word.
  1756.         cmp    ah,2
  1757.         je     copystr_4
  1758.         cmp    al,'/'                  ;/ indicates end of word.
  1759.         je    copystr_exit
  1760. copystr_4:
  1761.         inc    cx
  1762.         cmp    al,'%'                  ;See if translation needed.
  1763.         jne    copystr_6
  1764.         inc    bh            ;Set env/cmd line param flag
  1765.         or    bl,bl            ;See if already set.
  1766.         mov    bl,0            ;Clear caps flag
  1767.         jne    copystr_6         ;If caps set, trailing %
  1768.  
  1769.         cmp    byte ptr [si],7fh    ;Check for For loop var. If
  1770.         jne    copystr_5        ;  found, copy it removing
  1771.         stosb                ;  the extra 7f.
  1772.         lodsb
  1773.         inc    si
  1774.         jmp    short copystr_6
  1775. copystr_5:
  1776.         cmp    byte ptr [si],'9'       ;If char after % is number,
  1777.         ja     copystr_51        ;  this is a command line
  1778.         cmp    byte ptr [si],'0'       ;  parameter, else an env
  1779.         jae    copystr_6        ;  var.
  1780. copystr_51:
  1781.         inc    bl            ;Set caps flag
  1782. copystr_6:
  1783.         or    bl,bl
  1784.         je    copystr_7
  1785.         call    capschar
  1786. copystr_7:
  1787.         stosb                ;Save byte
  1788.         jmp    short copystr_1     ;Loop back.
  1789. copystr_exit:
  1790.         pop    dx
  1791.         ret
  1792. copy_string    endp
  1793.  
  1794. ;-----------------------------------------------------------------------------
  1795. ; INLINE CODE  Adds the necessary inline code to call a canned
  1796. ;        routine.
  1797. ; Entry:  AX - Offset of canned routine.
  1798. ;      CL - (low nibble) Method to pass parameter one
  1799. ;      CL - (high nibble) Method to pass parameter two
  1800. ;      CH - (low nibble) Call/Jump method
  1801. ;      DX - Parameter one
  1802. ;      BX - Parameter two
  1803. ;-----------------------------------------------------------------------------
  1804. inline_code    proc    near
  1805.         push    bp
  1806.         push    si            ;Save pointer to input buffer.
  1807.         push    di
  1808.         push    es
  1809.         les    di,codebuff_ptr     ;Point ES:DI to buffer
  1810.         mov    bp,cx
  1811.         and    cl,0fh            ;Look only at SI code nibble
  1812.         cmp    cl,1            ;Check for LEA SI
  1813.         jne    inline_1
  1814.         mov    si,offset code_leasi
  1815.         mov    [si+2],dx        ;Load paramter one
  1816.         mov    cx,code_leasi_size
  1817.         rep    movsb            ;Copy routine into COM file.
  1818.         jmp    short inline_10
  1819. inline_1:
  1820.         cmp    cl,2            ;Check for MOV SI
  1821.         jne    inline_2
  1822.         mov    si,offset code_movsi
  1823.         mov    [si+2],dx        ;Load parameter one
  1824.         mov    cx,code_movsi_size
  1825.         rep    movsb            ;Copy routine into COM file.
  1826.         jmp    short inline_10
  1827. inline_2:
  1828.         cmp    cl,3            ;Check for MOV SI Immediate
  1829.         jne    inline_10
  1830.         mov    si,offset code_movsiim
  1831.         mov    [si+1],dx        ;Load parameter one
  1832.         mov    cx,code_movsiim_size
  1833.         rep    movsb            ;Copy routine into COM file.
  1834. inline_10:
  1835.         mov    cx,bp            ;Get back code
  1836.         and    cl,0f0h
  1837.         cmp    cl,10h            ;Check for LEA DI
  1838.         jne    inline_11
  1839.         mov    si,offset code_leadi
  1840.         mov    [si+2],bx        ;Load paramter two
  1841.         mov    cx,code_leadi_size
  1842.         rep    movsb            ;Copy routine into COM file.
  1843.         jmp    short inline_13
  1844. inline_11:
  1845.         cmp    cl,20h            ;Check for MOV DI
  1846.         jne    inline_12
  1847.         mov    si,offset code_movdi
  1848.         mov    [si+2],bx        ;Load parameter two
  1849.         mov    cx,code_movdi_size
  1850.         rep    movsb            ;Copy routine into COM file.
  1851.         jmp    short inline_13
  1852. inline_12:
  1853.         cmp    cl,30h            ;Check for MOV immed DI
  1854.         jne    inline_13
  1855.         mov    si,offset code_movdiim
  1856.         mov    [si+1],bx        ;Load parameter two
  1857.         mov    cx,code_movdiim_size
  1858.         rep    movsb            ;Copy routine into COM file.
  1859. inline_13:
  1860.         mov    cx,bp
  1861.         and    ch,0fh
  1862.         jne    inline_20
  1863.         mov    si,offset code_call    ;Code to call the canned
  1864.         mov    cx,code_call_size    ;  routine.
  1865.         mov    [si+1],ax        ;Insert the destination offset.
  1866.         rep    movsb            ;Copy routine into COM file.
  1867.         jmp    short inline_30
  1868. inline_20:
  1869.         cmp    ch,01            ;Check for jmp
  1870.         jne    inline_21
  1871.         mov    si,offset code_jmp    ;Code to jmp to destination.
  1872.         mov    cx,code_jmp_size
  1873.         mov    [si+2],ax        ;Insert the destination offset.
  1874.         rep    movsb            ;Copy routine into COM file.
  1875.         jmp    short inline_30
  1876. inline_21:
  1877.         cmp    ch,02            ;Check for jc
  1878.         jne    inline_22
  1879.         mov    si,offset code_jc    ;Code to jc to destination.
  1880.         mov    cx,code_jc_size
  1881.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1882.         rep    movsb            ;Copy routine into COM file.
  1883.         jmp    short inline_30
  1884. inline_22:
  1885.         cmp    ch,03            ;Check for jnc
  1886.         jne    inline_23
  1887.         mov    si,offset code_jnc    ;Code to jnc to destination.
  1888.         mov    cx,code_jnc_size
  1889.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1890.         rep    movsb            ;Copy routine into COM file.
  1891.         jmp    short inline_30
  1892. inline_23:
  1893.         cmp    ch,04            ;Check for jmp displacment
  1894.         jne    inline_30
  1895.         mov    si,offset code_jmpdis    ;Code to jmp IP relative.
  1896.         mov    [si+1],ax
  1897.         mov    cx,code_jmpdis_size
  1898.         rep    movsb            ;Copy routine into COM file.
  1899. inline_30:
  1900.         mov    word ptr cs:codebuff_ptr,di
  1901.         pop    es
  1902.         pop    di
  1903.         pop    si
  1904.         pop    bp
  1905.         ret
  1906. inline_code    endp
  1907.  
  1908. ;-----------------------------------------------------------------------------
  1909. ; INCLUDE CODE - Appends the routine to the append list if necessary and
  1910. ;         returns the offset of the routine in the compiled program.
  1911. ; Entry:  BX - Pointer to header of canned routine to append.
  1912. ; Exit:   AX - Offset of canned routine in COM file.
  1913. ;-----------------------------------------------------------------------------
  1914. include_code    proc    near
  1915.         assume    ds:code,es:nothing
  1916.         push    cx
  1917.         push    dx
  1918.         mov    ax,[bx-4]        ;Get COM file offset
  1919.         or    ax,ax            ;If zero, routine has not
  1920.         jne    include_exit        ;  been appended.
  1921.         mov    cx,bx            ;Save pointer to new routine
  1922. ;
  1923. ;Address the prevous 'last' routine header.  Update that header, then use
  1924. ;information in that header to compute the offset of the new routine.
  1925. ;
  1926.         xchg    bx,last_routine
  1927.         mov    [bx],cx         ;Add code to chain.
  1928.         mov    ax,[bx-2]        ;Compute offset of new routine
  1929.         add    ax,[bx-4]        ;  by adding the offset of the
  1930.         sub    ax,[bx+2]        ;  prevous routine to its size.
  1931.         mov    bx,cx
  1932.  
  1933.         mov    cx,[bx+2]        ;Get number of called routines.
  1934.         add    ax,cx
  1935.         mov    [bx-4],ax        ;Set offset of code.
  1936.         jcxz    include_exit
  1937.         shr    cx,1            ;If this routine needs other
  1938.         add    bx,4            ;  routines, include them in
  1939.         push    ax            ;  the COM file.
  1940. include_1:
  1941.         push    cx
  1942.         push    bx
  1943.         mov    bx,[bx]
  1944.         call    include_code
  1945.         pop    bx
  1946.         mov    [bx],ax
  1947.         add    bx,2
  1948.         pop    cx
  1949.         loop    include_1
  1950.         pop    ax
  1951. include_exit:
  1952.         pop    dx
  1953.         pop    cx
  1954.         ret
  1955. include_code    endp
  1956. ;-----------------------------------------------------------------------------
  1957. ; PRINTMSG prints the message pointed to by DX to the screen.
  1958. ; Entry:  DX - pointer to ASCII message terminated by $
  1959. ;-----------------------------------------------------------------------------
  1960. printmsg    proc    near
  1961.         assume    ds:nothing,es:nothing
  1962.         push    ds
  1963.         push    cs
  1964.         pop    ds
  1965.         assume    ds:code
  1966.         mov    ah,9            ;Print message
  1967.         int    21h
  1968.         pop    ds
  1969.         ret
  1970. printmsg    endp
  1971.  
  1972. ;-----------------------------------------------------------------------------
  1973. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  1974. ; Entry:  DX - pointer to ASCII message terminated by $
  1975. ;-----------------------------------------------------------------------------
  1976. printmsgcr    proc    near
  1977.         assume    ds:nothing,es:nothing
  1978.         push    dx
  1979.         call    printmsg
  1980.         mov    dx,offset endmsg
  1981.         call    printmsg
  1982.         pop    dx
  1983.         ret
  1984. printmsgcr    endp
  1985.  
  1986. ;-----------------------------------------------------------------------------
  1987. ; HEX2ASC converts a binary number to ASCII and prints it to the screen.
  1988. ; Entry:  AX - binary number
  1989. ;-----------------------------------------------------------------------------
  1990. hex2asc     proc near
  1991.         assume    ds:nothing,es:nothing
  1992.         push    bx
  1993.         mov    cx,5            ;Allow max of five digits
  1994. hex_loop1:
  1995.         xor    dx,dx            ;Clear high word
  1996.         mov    bx,10            ;Load number base
  1997.         div    bx            ;Divide by base (10)
  1998.         add    dl,30h            ;Convert to ascii
  1999.         push    dx            ;Save digit on stack
  2000.         loop    hex_loop1
  2001.         mov    cx,5            ;Allow max of five digits
  2002.         mov    bl,"0"                  ;Set leading zero indicator
  2003. hex_loop2:
  2004.         pop    dx            ;Get digit off stack
  2005.         or    bl,dl            ;Don't print leading zeros.
  2006.         cmp    bl,"0"                  ;The first non zero will
  2007.         je    hex_1            ;  change bl to non-zero.
  2008.         mov    ah,2            ;DOS character output
  2009.         int    21h
  2010. hex_1:
  2011.         loop    hex_loop2
  2012. hex_exit:
  2013.         pop    bx
  2014.         ret
  2015. hex2asc     endp
  2016.  
  2017. ;-----------------------------------------------------------------------------
  2018. ; LOADBATFILE loads the input BAT file.
  2019. ; Entry:  DS:SI - pointer to the name of the file to open
  2020. ; Exit:      CF - clear if successful
  2021. ;
  2022. ;  Support for BAT files larger than 16 K is not currently implimented.
  2023. ;-----------------------------------------------------------------------------
  2024. loadbatfile    proc    near
  2025.         assume    cs:code,ds:code
  2026.         push    di
  2027.         push    si
  2028.         mov    bx,file_handle
  2029.         cmp    bx,-1
  2030.         jne    loadfile_3
  2031.         mov    dx,si            ;Save filename pointer
  2032.         mov    di,offset outfile_name    ;Point DI to buffer to hold
  2033.         mov    cx,8            ;  the output file name.
  2034. loadfile_1:
  2035.         lodsb                ;Copy the name until the
  2036.         cmp    al,' '            ;  extension is reached.
  2037.         je    loadfile_2
  2038.         cmp    al,'.'
  2039.         je     loadfile_2
  2040.         stosb
  2041.         loop    loadfile_1
  2042. loadfile_2:
  2043.         mov    si,offset com_string    ;Append COM extension to
  2044.         movsb                ;  output file name.
  2045.         movsw
  2046.         movsw
  2047.         mov    si,dx            ;Get back filename pointer
  2048.         mov    bl,1            ;Find end of filename
  2049.         call    scan4char
  2050.         dec    si
  2051.         mov    byte ptr [si],0     ;Make filename ASCIIZ.
  2052.         mov    ax,3d00h        ;Open file (Read only)
  2053.         int    21h
  2054.         jc    loadfile_error
  2055.         mov    bx,ax            ;Copy file handle
  2056. ;
  2057. ;Read contents into file buffer.
  2058. ;
  2059. loadfile_3:
  2060.         mov    file_handle,-1        ;Assume file completely read.
  2061.         mov    ah,3fh            ;Read input BAT file into
  2062.         mov    dx,inbuff_ptr        ;  memory above stack space
  2063.         mov    cx,inbuff_size         ;Get size of buffer
  2064.         sub    cx,4
  2065.         int    21h
  2066.         mov    di,dx            ;Point DI to end of the file
  2067.         add    di,ax
  2068.         cmp    ax,cx            ;Check if complete file read.
  2069.         jb     loadfile_4
  2070.  
  2071.         std                ;If there is more of the file
  2072.         push    dx            ;  to read, scan backwards to
  2073.         mov     dx,ax            ;  the end of the last line.
  2074.         mov    cx,ax            ;Get file length
  2075.  
  2076.         mov    al,13            ;Scan for last CR
  2077.         cmp    [di-1],al         ;If last byte in buffer a CR
  2078.         jne    loadfile_30        ;  back up 2 CRs.  Fixes bug
  2079.         dec    di            ;  in Ver 1.4.
  2080.         dec    di
  2081.         dec    cx
  2082.         dec    cx
  2083. loadfile_30:
  2084.  
  2085.         repne    scasb
  2086.         cld                ;Reset string flag
  2087.         add      di,3
  2088.         add    cx,3
  2089.         xchg    cx,dx            ;Compute the number of bytes
  2090.         sub    dx,cx            ;  to back up the file pointer
  2091.         mov    cx,0            ;  The filepointer is a 32
  2092.         jz    loadfile_31        ;  bit number in CX,DX.
  2093.         dec    cx
  2094. loadfile_31:
  2095.         mov    ax,4201h        ;Move file pointer backwards
  2096.         int    21h
  2097.         mov    file_handle,bx
  2098.         pop    dx
  2099. loadfile_4:
  2100.         mov    ax,1a1ah
  2101.         stosw                ;Append EOF bytes.
  2102.         stosw
  2103.  
  2104.         cmp    file_handle,-1
  2105.         jne    loadfile_exit
  2106.         mov    ah,3eh            ;Close file.
  2107.         int    21h
  2108. loadfile_exit:
  2109.         clc
  2110. loadfile_exit1:
  2111.         pop    si
  2112.         pop    di
  2113.         ret
  2114. loadfile_error:
  2115.         stc
  2116.         mov    dx,offset errmsg2    ;Bad filename specified.
  2117.         jmp    short loadfile_exit1
  2118. loadbatfile    endp
  2119.  
  2120. ;-----------------------------------------------------------------------------
  2121. ; SCAN4CHAR scans a string to find the first character.
  2122. ; Entry:  SI - pointer to ASCII string
  2123. ;      BL - 0 = find next char,
  2124. ;              1 = find next space,
  2125. ;              2 = find end of line,
  2126. ;              3 = find next space or =.
  2127. ; Exit:   AL - matching character
  2128. ;      SI - pointer to matching character
  2129. ;      CF - set if carriage return or EOF found
  2130. ;-----------------------------------------------------------------------------
  2131. scan4char    proc near
  2132.         assume    ds:nothing,es:nothing
  2133. scan4loop:
  2134.         lodsb
  2135.         cmp    al,13            ;Check for carriage return.
  2136.         je    scan4_eol
  2137.         cmp    al,1ah            ;Check for end of file char.
  2138.         jne    scan4_1
  2139. scan4_eol:
  2140.         stc
  2141.         jmp    short scan4_exit1
  2142. scan4_1:
  2143.         cmp    bl,3
  2144.         je    scan4_equal
  2145.         cmp    bl,1            ;Check if searching for space,
  2146.         je    scan4_space         ;  character, or end of line.
  2147.         ja    scan4loop
  2148.         cmp    al," "                  ;Check for space or other
  2149.         jbe    scan4loop        ;  'white' characters.
  2150.         jmp    short scan4_exit
  2151. scan4_equal:
  2152.         cmp    al,"="            ;Check for exit
  2153.         je    scan4_exit
  2154. scan4_space:
  2155.         cmp    al," "                  ;Check for characters.
  2156.         ja    scan4loop
  2157. scan4_exit:
  2158.         dec    si            ;Back up before character
  2159.         clc
  2160. scan4_exit1:
  2161.         ret
  2162. scan4char    endp
  2163.  
  2164. ;============================================================================
  2165. ;Routines used by compiled program.
  2166. ;============================================================================
  2167. ;!!--------------------------------------------------------------------------
  2168. ;Code fragments used to call canned routines.
  2169. ;----------------------------------------------------------------------------
  2170. code_call    proc    near
  2171.         mov    ax,1234h        ;Set address to call routine.
  2172.         call    ax            ;Call canned routine.
  2173. code_call_end    =    $
  2174. code_call    endp
  2175.  
  2176. code_jmp    proc    near
  2177.         mov    ax,[bp+1234h]        ;Set address to call routine.
  2178.         jmp    ax            ;Jump to new offset.
  2179. code_jmp_end    =    $
  2180. code_jmp    endp
  2181.  
  2182. code_jc     proc    near
  2183.         jnc    code_jc_end        ;Jump over long jmp
  2184.         jmp    initialize        ;This jmp will be modified
  2185. code_jc_end    =    $
  2186. code_jc     endp
  2187.  
  2188. code_jnc    proc    near
  2189.         jc    code_jnc_end        ;Skip over long jmp
  2190.         jmp    initialize        ;This jmp will be modified
  2191. code_jnc_end    =    $
  2192. code_jnc    endp
  2193.  
  2194. code_jmpdis    proc    near
  2195.         jmp    initialize        ;This jmp will be modified
  2196. code_jmpdis_end =    $
  2197. code_jmpdis    endp
  2198.  
  2199. code_leasi    proc    near
  2200.         lea    si,[bp+1234h]        ;Load address of data
  2201. code_leasi_end    =    $
  2202. code_leasi    endp
  2203.  
  2204. code_movsi    proc    near
  2205.         mov    si,[bp+1234h]        ;Load data
  2206. code_movsi_end    =    $
  2207. code_movsi    endp
  2208.  
  2209. code_movsiim    proc    near
  2210.         mov    si,1234h        ;Load immediate data
  2211. code_movsiim_end  =    $
  2212. code_movsiim    endp
  2213.  
  2214. code_leadi    proc    near
  2215.         lea    di,[bp+1234h]        ;Load address of data
  2216. code_leadi_end    =    $
  2217. code_leadi    endp
  2218.  
  2219. code_movdi    proc    near
  2220.         mov    di,[bp+1234h]        ;Load data
  2221. code_movdi_end    =    $
  2222. code_movdi    endp
  2223.  
  2224. code_movdiim    proc    near
  2225.         mov    di,1234h        ;Load immediate data
  2226. code_movdiim_end  =    $
  2227. code_movdiim    endp
  2228.  
  2229. ;----------------------------------------------------------------------------
  2230. ;Predefined data needed for all compiled programs.
  2231. ;----------------------------------------------------------------------------
  2232. data_start    =    $
  2233. code_start    dw    ?            ;Offset of main code routine
  2234. stack_ptr    dw    ?            ;Offset of end of code + stack
  2235. prog_segsize    dw    ?            ;Size of COM prog in paragraphs
  2236. prse_buff_ptr    dw    ?            ;Buffer for parsing strings
  2237. prs2_buff_ptr    dw    ?            ;Buffer for parsing strings
  2238. exec_buff_ptr    dw    ?            ;Buffer for exec function
  2239. for_buff_ptr    dw    ?            ;Buffer for For loop variables
  2240. floop_ptr    dw    ?            ;Pointer to for loop string
  2241. file_handle1    dw    ?            ;Saved handle of std output
  2242. file_handle2    dw    ?            ;Handle of output file
  2243. file_handle3    dw    ?            ;Saved handle of std input
  2244. file_handle4    dw    ?            ;Handle of input file
  2245. label_list_strt dw    ?            ;Offset into data of 1st label.
  2246. master_env    dw    ?            ;Segment of environment blk
  2247. version_num    dw    ?            ;DOS version number
  2248. proc_rc     db    ?            ;Return code of last program.
  2249. shift_cnt    db    ?            ;Count of shift parameter
  2250. data_end    =    $
  2251.  
  2252. ;----------------------------------------------------------------------------
  2253. ;INIT CODE Routine at the start of all compiled programs.
  2254. ;----------------------------------------------------------------------------
  2255. init_code_off    dw    100h            ;Pointer to offset in COM file
  2256. init_code_size    dw    offset init_code_end-offset init_code_start
  2257. init_code_next    dw    0            ;Ptr to next routine to append
  2258. init_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of
  2259. init_code_start =    $
  2260.  
  2261. init_code    proc    near
  2262.         assume    cs:code,ds:code,es:code,ss:code
  2263.         jmp    init_code_1
  2264.         db    "Compiled by BAT2EXEC 1.5",13,10
  2265.           db    "PC Magazine ",254," Douglas Boling",13,10,1ah
  2266. init_code_1:
  2267.         cld
  2268.         mov    bp,ds:[offset data_start_ptr - offset init_code + 100h]
  2269.         mov    bp,[bp]
  2270.         mov    sp,com_stack_ptr    ;Move stack pointer
  2271.         mov    bx,com_prog_size    ;Reduce memory allocation
  2272.         mov    ah,4ah            ;Resize memory block
  2273.         int    21h
  2274.         mov    ax,ds:[2ch]        ;Get program environment seg
  2275.         mov    environment_seg,ax    ;  use unless SET cmd used.
  2276.         mov    bx,code_start_ptr    ;Get starting code offset
  2277.         jmp    bx            ;Jump to start of code.
  2278. data_start_ptr    dw    ?            ;Offset of data area.
  2279. init_code    endp
  2280. init_code_end    =    $
  2281.  
  2282. ;----------------------------------------------------------------------------
  2283. ;END CODE Routine appended at the end of all compiled programs.
  2284. ;----------------------------------------------------------------------------
  2285. end_code_off    dw    0            ;Pointer to offset in COM file
  2286. end_code_size    dw    offset end_code_end-offset end_code_start
  2287. end_code_next    dw    0            ;Ptr to next routine to append
  2288. end_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of r
  2289. end_code_start    =    $
  2290.  
  2291. end_code    proc    near
  2292.         assume    cs:code,ds:code
  2293.         mov    ax,4c00h        ;Terminate program
  2294.         int    21h
  2295. end_code    endp
  2296. end_code_end    =    $
  2297.  
  2298. ;----------------------------------------------------------------------------
  2299. ;ECHO MSG CODE Routine used print a string to the standard output device
  2300. ; Entry:  DS:SI - offset of string to print.
  2301. ;----------------------------------------------------------------------------
  2302. echo_msg_off    dw    0            ;Pointer to offset in COM file
  2303. echo_msg_size    dw    offset echo_msg_end-offset echo_msg_start
  2304. echo_msg_next    dw    0            ;Ptr to next routine to append
  2305. echo_msg_lnks    dw    0            ;Bytes in the dependancy header ;Number of r
  2306. echo_msg_start    =    $
  2307.  
  2308. echo_msg_code    proc    near
  2309.         assume    cs:code,ds:code
  2310.         mov    dl,[si]         ;Get character
  2311.         inc    si
  2312.         or    dl,dl
  2313.         je    echo_msg_1
  2314.         mov    ah,2            ;Print character
  2315.         int    21h
  2316.         jmp    short echo_msg_code
  2317. echo_msg_1:
  2318.         ret
  2319. echo_msg_code    endp
  2320. echo_msg_end    =    $
  2321.  
  2322. ;----------------------------------------------------------------------------
  2323. ;ECHO STATUS CODE Routine used to report the status of the echo flag.
  2324. ; Entry:  AL - Echo flag.
  2325. ;----------------------------------------------------------------------------
  2326. echo_stat_ptr    dw    0            ;Pointer to offset in COM file
  2327. echo_stat_size    dw    offset echo_stat_end-offset echo_stat_start
  2328. echo_stat_next    dw    0            ;Ptr to next routine to append
  2329. echo_stat_lnks    dw    0            ;Bytes in the dependancy header ;Number of
  2330. echo_stat_start =    $
  2331.  
  2332. echo_stat_code    proc    near
  2333.         assume    cs:code,ds:code
  2334.         call    echo_stat_1        ;Push IP on stack
  2335. echo_msg    db    "ECHO is $"
  2336. echo_on     db    "on",10,13,"$"
  2337. echo_off    db    "off",10,13,"$"
  2338. echo_stat_1:
  2339.         pop    dx            ;Pop offset of echo message
  2340.         push    ax            ;Save status of echo flag
  2341.         mov    ah,9
  2342.         int    21h
  2343.         add    dx,offset echo_on-offset echo_msg ;Point to 'on' msg
  2344.         pop    ax
  2345.         or    al,al            ;Check status of echo flag
  2346.         je    echo_report_1
  2347.         add    dx,offset echo_off-offset echo_on ;Point to 'off' msg
  2348.         add    dx,5            ;Point to off message.
  2349. echo_report_1:
  2350.         mov    ah,9            ;Print last part of echo stat
  2351.         int    21h
  2352.         ret
  2353. echo_stat_code    endp
  2354. echo_stat_end    =    $
  2355.  
  2356. ;----------------------------------------------------------------------------
  2357. ;PAUSE CODE Routine used pause execution of the COM file.
  2358. ;----------------------------------------------------------------------------
  2359. pause_ptr    dw    0            ;Pointer to offset in COM file
  2360. pause_size    dw    offset pause_end-offset pause_start
  2361. pause_next    dw    0            ;Ptr to next routine to append
  2362. pause_lnks    dw    0            ;Bytes in the dependancy header ;Number of rout
  2363. pause_start    =    $
  2364.  
  2365. pause_code    proc    near
  2366.         assume    cs:code,ds:code
  2367.         call    pause_1     ;Push IP on stack
  2368. pause_msg    db    "Strike any key when ready...",13,10,"$"
  2369. pause_1:
  2370.         pop    dx            ;Pop offset of message
  2371.         mov    ah,9            ;Print message.
  2372.         int    21h
  2373.  
  2374.         mov    ah,7            ;Keyboard unfiltered input
  2375.         int    21h            ;  without echo.
  2376.         ret
  2377. pause_code    endp
  2378. pause_end    =    $
  2379.  
  2380. ;----------------------------------------------------------------------------
  2381. ;SHIFT CODE Routine used shift the input parameters by one.
  2382. ;----------------------------------------------------------------------------
  2383. shift_ptr    dw    0            ;Pointer to offset in COM file
  2384. shift_size    dw    offset shift_end-offset shift_start
  2385. shift_next    dw    0            ;Ptr to next routine to append
  2386. shift_lnks    dw    0            ;Bytes in the dependancy header ;Number of rout
  2387. shift_start    =    $
  2388.  
  2389. shift_code    proc    near
  2390.         assume    cs:code,ds:code
  2391.         inc    byte ptr shift_count     ;Inc shift count.
  2392.         ret
  2393. shift_code    endp
  2394. shift_end    =    $
  2395.  
  2396. ;-----------------------------------------------------------------------------
  2397. ; SCAN_CHAR scans a string to find the first character.
  2398. ; Entry:  SI - pointer to ASCII string
  2399. ;      DL - 0 = find next char, 1 = find next space
  2400. ;      CX - file length
  2401. ; Exit:   AL - first nonspace character
  2402. ;      CF - set if carriage return found
  2403. ;-----------------------------------------------------------------------------
  2404. scan4_off    dw    0            ;Pointer to offset in COM file
  2405. scan4_size    dw    offset scan4_end - offset scan4_start
  2406. scan4_next    dw    0            ;Ptr to next routine to append
  2407. scan4_lnks    dw    0
  2408. scan4_start    =    $
  2409.  
  2410. scan_char    proc near
  2411.         assume    ds:nothing,es:nothing
  2412. scan_loop:
  2413.         lodsb
  2414.         cmp    al,9            ;See if char is tab
  2415.         je    scan_space        ;If before, end of line
  2416.  
  2417.         cmp    al,";"
  2418.         je    scan_space
  2419.         cmp    al,","
  2420.         je    scan_space
  2421.  
  2422.         cmp    al," "                  ;See if char is space.
  2423.         jb    scan_eol        ;If before, end of line
  2424.         je    scan_space
  2425.         or    dl,dl            ;Not space, if looking
  2426.         jne    scan_loop        ;  for space continue.
  2427.         jmp    short scan_exit
  2428. scan_space:
  2429.         or    dl,dl            ;Space found, see if looking
  2430.         je    scan_loop        ;  for one.
  2431. scan_exit:
  2432.         clc
  2433.         ret
  2434. scan_eol:
  2435.         stc
  2436.         ret
  2437. scan_char    endp
  2438. scan4_end    =    $
  2439.  
  2440. ;-----------------------------------------------------------------------------
  2441. ; GETMEMBER  returns a pointer to the Nth word in a line.
  2442. ; Entry:     SI - pointer to line of words
  2443. ;         DH - number of the word to return
  2444. ; Exit:      SI - pointer to word
  2445. ;         CF - Set if word not in line.
  2446. ;-----------------------------------------------------------------------------
  2447. getmember_scan4 equ    [bx-6]
  2448. getmember_off    dw    0            ;Pointer to offset in COM file
  2449. getmember_size    dw    offset getmember_end - offset getmember_start
  2450. getmember_next    dw    0            ;Ptr to next routine to append
  2451. getmember_lnks    dw    2            ;Bytes in the dependancy header
  2452. getmember_start =    $
  2453.         dw    offset scan4_next    ;Offset of called routine.
  2454.  
  2455. getmember    proc    near
  2456.         assume    cs:code,ds:code,es:code,ss:code
  2457.         push    bx
  2458.         call    getmember_0
  2459. getmember_0:
  2460.         pop    bx
  2461. getmember_1:
  2462.         xor    dl,dl
  2463.         call    getmember_scan4     ;Find next word
  2464.         jc    getmember_notfound
  2465.         dec    dh            ;Dec parameter count
  2466.         jle    getmember_2
  2467.         inc    dl
  2468.         call    getmember_scan4     ;Find next space
  2469.         jc    getmember_exit
  2470.         jmp    short getmember_1    ;If not done, loop back.
  2471. getmember_2:
  2472.         dec    si            ;Backup to 1st char in word.
  2473.         clc
  2474. getmember_exit:
  2475.         pop    bx
  2476.         ret
  2477. getmember_notfound:
  2478.         stc
  2479.         jmp    short getmember_exit
  2480. getmember    endp
  2481. getmember_end    =    $
  2482.  
  2483. ;-----------------------------------------------------------------------------
  2484. ; PROCSTRING processes a string to convert any environment variables or
  2485. ;         command line variables.
  2486. ; Entry:  DS:SI - ASCIIZ string to process
  2487. ;      ES:DI - pointer to output buffer.
  2488. ; Exit:   DS:SI - pointer to beginning of new ASCIIZ string.
  2489. ;     [SI-1] - Length of new string.
  2490. ;-----------------------------------------------------------------------------
  2491. procstr_cmdl    equ    [bx-8]
  2492. procstr_env    equ    [bx-6]
  2493. procstr_off    dw    0            ;Pointer to offset in COM file
  2494. procstr_size    dw    offset procstr_end - offset procstr_start
  2495. procstr_next    dw    0            ;Ptr to next routine to append
  2496. procstr_lnks    dw    4            ;Bytes in the dependancy header
  2497.  
  2498. procstr_start    =    $
  2499.         dw    offset subparm_next    ;Offset of called routines.
  2500.         dw    offset subenv_next
  2501.  
  2502. procstr_code    proc    near
  2503.         assume    cs:code,ds:code,es:code
  2504.         push    bx
  2505.         call    procstr_0
  2506. procstr_0:
  2507.         pop    bx
  2508.         push    di
  2509.         push    si
  2510.         mov    ah,BUFF_SIZE        ;Set size of buffer
  2511. procstr_1:
  2512.         lodsb                ;Get byte from string
  2513.         or    al,al            ;Check for end of string
  2514.         je    procstr_exit
  2515.         cmp    al,"%"                  ;See if special character
  2516. procstr_jmp:
  2517.         je    procstr_3        ;Yes, process special char.
  2518. procstr_2:
  2519.         stosb                ;Store byte from string
  2520.         dec    ah
  2521.         jne    procstr_1
  2522. procstr_exit:
  2523.         xor    al,al            ;Force zero byte end.
  2524.         stosb
  2525.         pop    si
  2526.         pop    di
  2527.         mov    bl,BUFF_SIZE
  2528.         sub    bl,ah
  2529.         mov    ds:[di-1],bl        ;Store length of string
  2530.         pop    bx
  2531.         ret
  2532. ;
  2533. ;A percent sign has been found indicating a 'soft' parameter.  Three types of
  2534. ;soft parameters are allowed; command line parameter, environment variable,
  2535. ;and for loop parameter.
  2536. ;
  2537. procstr_3:
  2538.         lodsb                ;Get next character
  2539.         dec    cx
  2540.         cmp    al,"%"                  ;If double %, include one
  2541.         je    procstr_2        ;  in string.
  2542.         cmp    al,7fh            ;See if for loop var
  2543.         jne    procstr_32
  2544.         push    si
  2545.         mov    si,forloop_ptr        ;Get ptr to for loop string
  2546. procstr_30:
  2547.         lodsb
  2548.         cmp    al,0            ;If zero, end of string
  2549.         je    procstr_31
  2550.         stosb
  2551.         dec    ah            ;Dec buffer size counter
  2552.         jne    procstr_30        ;If buffer not full, continue
  2553. procstr_31:
  2554.         pop    si            ;Get back source string pointer
  2555.         jmp    short procstr_4
  2556. procstr_32:
  2557.         mov    dh,al            ;Copy and check to see if
  2558.         sub    dh,"0"                  ;  the next char is a number.
  2559.         jb    procstr_5        ;  If so, assume a line
  2560.         cmp    dh,9            ;  parameter.
  2561.         ja    procstr_5
  2562.         call    procstr_cmdl        ;Call cmd line param routine
  2563. procstr_4:
  2564.         or    ah,ah
  2565.         jne    procstr_1
  2566.         jmp    short procstr_exit    ;If at end of string, done
  2567. procstr_5:
  2568.         dec    si            ;Backup to 1st character
  2569.         inc    cx
  2570.         call    procstr_env
  2571.         jmp    short procstr_4
  2572. procstr_code    endp
  2573. procstr_end    =    $
  2574.  
  2575. ;-----------------------------------------------------------------------------
  2576. ; SUBLINEPARAM substitutes a parameter from the command line.
  2577. ; Entry:  ES:DI - pointer to buffer to copy the line parameter
  2578. ;         DH - binary number of the line parameter
  2579. ;         AH - size of buffer
  2580. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2581. ;         CX - remaining length of the buffer
  2582. ;-----------------------------------------------------------------------------
  2583. subparm_getmem    equ    [bx-6]
  2584. subparm_off    dw    0            ;Pointer to offset in COM file
  2585. subparm_size    dw    offset subparm_end - offset subparm_start
  2586. subparm_next    dw    0            ;Ptr to next routine to append
  2587. subparm_lnks    dw    2            ;Bytes in the dependancy header
  2588. subparm_start    =    $
  2589.         dw    offset getmember_next    ;Offset of called routine.
  2590.  
  2591. sublineparam    proc    near
  2592.         assume    cs:code,ds:code,es:code,ss:code
  2593.         push    bx
  2594.         call    sublineparam_1
  2595.         db    "DOS2X",0        ;Dummy %0 parameter for DOS 2x
  2596. sublineparam_1:
  2597.         pop    bx
  2598.         push    cx
  2599.         push    si
  2600.         push    ds
  2601.         mov    si,80h            ;Get ptr to cmd line
  2602.         xor    cx,cx
  2603.         mov    cl,[si]         ;Get number of chars in buffer.
  2604.         inc    si            ;Point to data
  2605.         add    dh,ds:shift_count    ;Add in shift count.
  2606.         or    dh,dh            ;Check count of param to find.
  2607.         jnz    sublineparam_12
  2608. ;
  2609. ;For parameter 0, attempt to look in the env block for the name of the prog.
  2610. ;
  2611.         push    ax            ;Save buffer size in AH
  2612.         mov    ah,30h            ;Get DOS version
  2613.         int    21h            ;If DOS 2.x, program nane not
  2614.         cmp    al,2            ;  in the env segment.  Use
  2615.         pop    ax
  2616.         ja    sublineparam_10        ;  dunny name instead.
  2617.         lea    si,[bx]            ;Point to dummy parameter
  2618.         jmp    short sublineparam_2
  2619. sublineparam_10:
  2620.         push    es
  2621.         push    di
  2622.         mov    es,ds:[2ch]        ;Get segment of local env
  2623.         xor    al,al
  2624.         xor    di,di
  2625.         mov    cx,8000h
  2626. sublineparam_11:
  2627.         repne    scasb            ;Find double zero
  2628.         scasb
  2629.         jne    sublineparam_11
  2630.         scasw                ;Scan to name
  2631.         mov    si,di            ;Copy pointer to name
  2632.         pop    di
  2633.         pop    es
  2634.         mov    ds,ds:[2ch]
  2635.         jmp    short sublineparam_2
  2636. sublineparam_12:
  2637.         call    subparm_getmem        ;Get pointer to proper word.
  2638.         jc    sublineparam_exit
  2639. sublineparam_2:
  2640.         lodsb                ;Get character from parameter
  2641.         cmp    al," "                  ;If space, parameter done
  2642.         jbe    sublineparam_exit
  2643.  
  2644.         cmp    al,";"            ;Comma and semicolon also
  2645.         je    sublineparam_exit    ;  delimit a command line
  2646.         cmp    al,","            ;  parameter.
  2647.         je    sublineparam_exit
  2648.  
  2649.         stosb
  2650.         dec    ah            ;Dec buffer size counter
  2651.         jnz    sublineparam_2
  2652. sublineparam_exit:
  2653.         pop    ds
  2654.         pop    si
  2655.         pop    cx
  2656.         pop    bx
  2657.         ret
  2658. sublineparam    endp
  2659. subparm_end    =    $
  2660. ;-----------------------------------------------------------------------------
  2661. ; SUBENVVAR substitutes a parameter from the program environment block.
  2662. ; Entry:  DS:SI - pointer to enviroment variable.
  2663. ;      ES:DI - pointer to buffer.
  2664. ;         AH - size of buffer.
  2665. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2666. ;      DS:SI - pointer to the character after the line parameter number
  2667. ;         CX - remaining free bytes in the buffer.
  2668. ;-----------------------------------------------------------------------------
  2669. subenv_srchenv    equ    [bx-6]
  2670. subenv_off    dw    0            ;Pointer to offset in COM file
  2671. subenv_size    dw    offset subenv_end-offset subenv_start
  2672. subenv_next    dw    0            ;Ptr to next routine to append
  2673. subenv_lnks    dw    2            ;Bytes in the dependancy header
  2674. subenv_start    =    $
  2675.         dw    offset searchenv_next    ;Call to search environment blk
  2676.  
  2677. subenvvar    proc    near
  2678.         assume    cs:code,ds:code,es:code,ss:code
  2679.         push    bx
  2680.         call    subenvvar_0
  2681. subenvvar_0:
  2682.         pop    bx
  2683.         push    ds
  2684. ;
  2685. ;Compute the length of the variable name.
  2686. ;
  2687.         mov    cx,255
  2688.         push    di            ;Save pointer to internal buff
  2689.         mov    di,si            ;Compute the length of the
  2690.         mov    dx,cx            ;  environment variable by
  2691.         mov    al,"%"                  ;  searching for the trailing
  2692.         repne    scasb            ;  % sign.
  2693.         sub    dx,cx            ;Compute length of variable.
  2694.         dec    dx            ;Subtract % byte from length.
  2695.         mov    cx,di
  2696.         pop    di
  2697.         push    cx            ;Save ptr to end of var
  2698.         call    subenv_srchenv        ;Search environment block.
  2699.         jc    short subenvvar_exit    ;CF set, variable not found.
  2700. ;
  2701. ;Environment variable found. Substitute into string.
  2702. ;
  2703. subenvvar_1:
  2704.         lodsb                ;Get env var character
  2705.         or    al,al            ;Check for end of string
  2706.         je    subenvvar_exit
  2707.         stosb                ;Save character in string
  2708.         dec    ah            ;Dec buffer size count.
  2709.         jne    subenvvar_1        ;If buffer not full, continue
  2710. subenvvar_exit:
  2711.         pop    si            ;Restore string pointer
  2712.         pop    ds            ;Restore segment register
  2713.         pop    bx
  2714.         ret
  2715. subenvvar    endp
  2716. subenv_end    =    $
  2717.  
  2718. ;-----------------------------------------------------------------------------
  2719. ; SEARCH_ENV scans the environment block for a string.
  2720. ; Entry:  DS:SI - pointer to ASCII string
  2721. ;         DX - length of string
  2722. ; Exit:   DS:SI - points to first character of environment string
  2723. ;         CF - clear if string found
  2724. ;-----------------------------------------------------------------------------
  2725. searchenv_off    dw    0               ;Pointer to offset in COM file
  2726. searchenv_size    dw    offset searchenv_end - offset searchenv_start
  2727. searchenv_next    dw    0               ;Ptr to next routine to append
  2728. searchenv_lnks    dw    0
  2729. searchenv_start =    $
  2730.  
  2731. search_env    proc near
  2732.         assume    ds:nothing,es:nothing
  2733.         push    bx
  2734.         push    cx
  2735.         push    di
  2736.         push    es
  2737.         mov    es,environment_seg    ;Get seg of environment blk
  2738.         xor    di,di            ;Point ES:DI to environment.
  2739.         mov    bx,si            ;Save pointer to var name
  2740. search_env_1:
  2741.         mov    si,bx            ;Get back ptr to var name.
  2742.         mov    cx,dx            ;Compare env var to var in
  2743.         repe    cmpsb            ;  string.
  2744.         je    search_env_2        ;Variable found, exit loop
  2745.         xor    al,al            ;Find next environment var.
  2746.         mov    cx,-1            ;Scan the entire segment.
  2747.         repne    scasb
  2748.         cmp    byte ptr es:[di],0    ;If double zero, end of env
  2749.         jne    search_env_1        ;  block. else, loop back.
  2750. search_env_not_found:
  2751.         mov    si,di            ;Point SI to end of env data
  2752.         push    es
  2753.         pop    ds
  2754.         stc
  2755.         jmp    short search_env_exit
  2756. search_env_2:
  2757. ;
  2758. ;Environment variable found. Point DS:SI to the string.
  2759. ;
  2760.         mov    si,di
  2761.         push    es            ;DS:SI points to env string
  2762.         pop    ds
  2763. search_env_3:
  2764.         lodsb                ;Move environment pointer past
  2765.         cmp    al,"="                  ;  the equals sign.
  2766.         jne    search_env_3
  2767.         cmp    byte ptr [si],0
  2768.         je    search_env_not_found
  2769. search_env_4:
  2770.         lodsb                ;Move pointer to first
  2771.         or    al,al            ;  non-space character.
  2772.         jb    search_env_5
  2773.         cmp    al," "
  2774.         jb    search_env_4
  2775. search_env_5:
  2776.         dec    si
  2777.         clc
  2778. search_env_exit:
  2779.         pop    es
  2780.         pop    di
  2781.         pop    cx
  2782.         pop    bx
  2783.         ret
  2784. search_env    endp
  2785. searchenv_end    =    $
  2786.  
  2787. ;----------------------------------------------------------------------------
  2788. ;EXTERNAL CMD  Routine used to launch programs from the COM file.
  2789. ; Entry   DS:SI - Pointer to the ASCIIZ program name
  2790. ;      ES:DI - Pointer to the ASCIIZ command line tail
  2791. ;----------------------------------------------------------------------------
  2792. extern_intcmd    equ    [bx-14]
  2793. extern_echomsg    equ    [bx-12]
  2794. extern_parspath equ    [bx-10]
  2795. extern_launch    equ    [bx-8]
  2796. extern_ifexits    equ    [bx-6]
  2797. extern_pathcnt    equ    [bx]
  2798. extern_path_var equ    [bx+1]
  2799. extern_file_ext equ    [bx+6]
  2800. extern_filename equ    [bx+15]
  2801. extern_filetail equ    [bx+17]
  2802. extern_lostmsg    equ    [bx+19]
  2803. extern_cmdparm    equ    [bx+46]
  2804. extern_pathflag    equ    [bx+49]
  2805. external_ptr    dw    0            ;Pointer to offset in COM file
  2806. external_size    dw    offset external_end - offset external_start
  2807. external_next    dw    0            ;Ptr to next routine to append
  2808. external_lnks    dw    10            ;Bytes in the dependancy header ;Number of
  2809. external_start    =    $
  2810.         dw    intcmd_next        ;Call to launch COMMAND.COM
  2811.         dw    echo_msg_next        ;Call to display string
  2812.         dw    parsepath_next        ;Call to get part of path
  2813.         dw    launch_next        ;Call execute file
  2814.         dw    ifexist_next        ;Call to find file
  2815.  
  2816. external_code    proc    near
  2817.         assume    cs:code,ds:code
  2818.         push    bx
  2819.         call    external_0
  2820.         db    0            ;Cnt to track path search.
  2821.         db    "PATH="
  2822.         db    "COMEXEBAT"
  2823.         dw    0            ;Pointer to filename
  2824.         dw    0            ;Pointer to command line tail
  2825.         db    "Bad command or file name",13,10,0
  2826.         db    "/C "
  2827.         db    0            ;Flag for path search
  2828. external_0:
  2829.         pop    bx            ;Get pointer to local vars.
  2830.         mov    extern_filename,si    ;Save ptr to file name
  2831.         mov    extern_filetail,di    ;Save ptr to command line tail
  2832.         mov    dx,exec_buff         ;Get pointer to free buffer.
  2833.         add    dx,4            ;Make room for /C if needed.
  2834.         mov    byte ptr extern_pathflag,0
  2835.         mov    byte ptr extern_pathcnt,0
  2836. ;Parse path to generate filename.
  2837. external_1:
  2838.         mov    di,dx            ;Get ptr to start of buffer
  2839.         xor    cx,cx            ;Check to see if we need to
  2840.         or    cl,extern_pathcnt    ;  check the directorys in
  2841.         jne    external_19        ;  the path.
  2842. ;The first time through, parse the name without using the path.
  2843.         push    dx
  2844.         push    si
  2845.         xor    dx,dx            ;Assume default drive
  2846.         cmp    byte ptr [si+1],':'    ;See if drive specified
  2847.         jne    external_11
  2848.         mov    dl,[si]
  2849.         and    dl,0dfh            ;Set to upper case
  2850.         sub    dl,'@'            ;Convert ASCII to number
  2851.         movsw                ;Copy drive letter
  2852.         add    word ptr extern_filename,2  ;Don't use drive in path
  2853. external_11:
  2854.         cmp    byte ptr [si],'\'    ;See if starting at root.
  2855.         je    external_110
  2856.         mov    al,'\'            ;Start at root dir
  2857.         stosb
  2858.         push    si
  2859.         mov    si,di            ;Get pointer to buffer.
  2860.         mov    ah,47h            ;Get current directory
  2861.         int    21h
  2862.         pop    si
  2863.         xor    al,al
  2864.         mov    cx,64
  2865.         repne    scasb            ;Find end of directory string
  2866.         dec    di
  2867.         cmp    byte ptr [di-1],'\'    ;Unless at root dir, add
  2868.         je     external_110
  2869.         mov    al,'\'
  2870.         stosb
  2871. external_110:
  2872.         xor    ax,ax
  2873. external_12:
  2874.         lodsb                ;Get a byte
  2875.         cmp    ax,2e2eh        ;See if we need to back up
  2876.         jne    external_13        ;  one directory.
  2877.         std
  2878.         mov    al,'\'            ;Scan backwards to erase
  2879.         mov    cx,18            ;  last directory.
  2880.         repne    scasb
  2881.         repne    scasb
  2882.         cld
  2883.         inc    di
  2884.         jmp    short external_12
  2885. external_13:
  2886.         stosb
  2887.         mov    ah,al            ;Copy last character.
  2888.         cmp    al,'\'            ;See if name specifies a path
  2889.         jne    external_14
  2890.         inc    byte ptr extern_pathflag
  2891. external_14:
  2892.         cmp    al,0
  2893.         jne    external_12
  2894. external_15:
  2895.         dec    di            ;Since DOS does not let the
  2896.         mov    dx,di            ;  user specify the file ext.
  2897.         std                ;  scan back to make sure one
  2898.         mov    cx,5            ;  is not attached.
  2899.         mov    al,'.'
  2900.         repne   scasb
  2901.         cld
  2902.         jne    external_16
  2903.         inc    di
  2904.         mov    dx,di
  2905. external_16:
  2906.         mov    di,dx
  2907.         pop    si
  2908.         pop    dx
  2909.         jmp    short external_4
  2910. ;Parse the path string to search remaining directorys.
  2911. external_19:
  2912.         cmp    byte ptr extern_pathflag,0  ;If a complete path was
  2913.         jne    external_badcmd            ;  specified, don't search
  2914.         mov    si,extern_filename        ;  the path.
  2915.         call    extern_parspath
  2916.         jnc    external_2        ;If we have checked all
  2917. external_badcmd:
  2918.         lea    si,extern_lostmsg    ;  directories in the path,
  2919.         call    extern_echomsg        ;  display file not found msg.
  2920.         jmp    short external_exit
  2921.  
  2922. ;Append filename to the end of the path.
  2923. external_2:
  2924.         mov    cx,73            ;Max length of filename
  2925. external_3:
  2926.         lodsb
  2927.         cmp    al,' '                  ;See if end of word
  2928.         jbe    external_4
  2929.         cmp    al,'.'                  ;See if end of filename
  2930.         je    external_4
  2931.         stosb
  2932.         loop    external_3
  2933. external_4:
  2934.         mov    al,'.'                  ;Append '.' to filename
  2935.         stosb
  2936.         lea    si,extern_file_ext    ;Get pointer to extensions
  2937.         mov    cx,3            ;3 extension types COM EXE BAT
  2938. external_5:
  2939.         movsw                ;Append extension to filename
  2940.         movsb
  2941.         xor    al,al            ;Termainate with zero
  2942.         stosb
  2943.         push    dx
  2944.         push    si
  2945.         push    cx
  2946.         mov    si,dx            ;Get ptr to start of name
  2947.         call    extern_ifexits        ;Search for file
  2948.         pop    cx
  2949.         pop    si
  2950.         pop    dx
  2951.         jnc    external_6
  2952.         sub    di,4            ;Backup to file extension
  2953.         loop    external_5
  2954.         inc    byte ptr extern_pathcnt ;Look in the next path str
  2955.         jmp    external_1
  2956. external_6:
  2957.         cmp    cx,1            ;See if BAT extension
  2958.         jne    external_8
  2959.         lea    si,extern_cmdparm    ;Get pointer to /C
  2960.         sub    dx,3
  2961.         mov    di,dx            ;Get ptr to string buffer
  2962.         movsw                ;Copy /C param
  2963.         movsb
  2964.         xor    al,al
  2965.         mov    cx,252
  2966.         repne    scasb            ;Find end of filename
  2967.         mov    byte ptr [di-1],' '     ;Fill in zero with space
  2968.         mov    si,extern_filetail    ;Get ptr to command line tail
  2969.         cmp    [si-1],cl
  2970.         ja    external_7
  2971.         mov    cl,[si-1]        ;Get length of cmd line tail
  2972. external_7:
  2973.         rep    movsb
  2974.         mov    byte ptr [di],13    ;Append CR to cmd line.
  2975.         mov    si,dx            ;Get pointer to BAT filename
  2976.         mov    ax,di            ;Compute length of cmd line.
  2977.         sub    ax,dx
  2978.         mov    [si-1],al
  2979.         call    extern_intcmd        ;Launch COMMAND.COM
  2980.         jmp    short external_exit
  2981. external_8:
  2982.         mov    di,extern_filetail    ;Get ptr to command line tail
  2983.         dec    di            ;Back up to buffer length
  2984.         dec    byte ptr [di]        ;Sub CR from length
  2985.         push    di
  2986.         mov    si,dx            ;Get ptr to start of name
  2987.         call    extern_launch        ;Execute program
  2988.         pop    di
  2989.         inc    byte ptr [di]        ;Restore cmd line length
  2990. external_exit:
  2991.         pop    bx
  2992.         ret
  2993. external_code    endp
  2994. external_end    =    $
  2995.  
  2996. ;-----------------------------------------------------------------------------
  2997. ; PARSEPATH  Parses the PATH and returns a qualified directory from the path.
  2998. ; Entry:  ES:DI - pointer to destination buffer.
  2999. ;         CX - index into the path variable. (zero based.)
  3000. ; Exit:   ES:DI - pointer to ASCIIZ destination filename.
  3001. ;         CF - Set if past end of the path
  3002. ;-----------------------------------------------------------------------------
  3003. parsepath_srenv equ    [bx-6]
  3004. parsepath_off    dw    0             ;Pointer to offset in COM file
  3005. parsepath_size    dw    offset parsepath_end - offset parsepath_start
  3006. parsepath_next    dw    0             ;Ptr to next routine to append
  3007. parsepath_lnks    dw    2
  3008. parsepath_start =    $
  3009.         dw    offset searchenv_next     ;Call to search env block
  3010.  
  3011. parsepath    proc    near
  3012.         assume    cs:code,ds:code,es:code,ss:code
  3013.         push    bx
  3014.         call    parsepath_1
  3015.         db    "PATH"
  3016. parsepath_1:
  3017.         pop    bx
  3018.         push    dx
  3019.         push    si
  3020.         push    ds
  3021.         mov    dx,4            ;Length of PATH string
  3022.         mov    si,bx            ;Point SI to PATH string
  3023.         call    getcom_srchenv        ;PATH var ptr return in DS:SI
  3024. parsepath_2:
  3025.         dec    cx            ;Dec path segment count
  3026.         jcxz    parsepath_4
  3027. parsepath_3:
  3028.         lodsb                ;Get character
  3029.         or    al,al            ;See if end of path string
  3030.         je    parsepath_notfound
  3031.         cmp    al,';'                  ;See if end of path segment
  3032.         jne    parsepath_3
  3033.         jmp    short parsepath_2
  3034. parsepath_4:
  3035.         lodsb
  3036.         cmp    al,';'                  ;See if end of path segment
  3037.         je    parsepath_5
  3038.         or    al,al            ;See if end of path
  3039.         je    parsepath_5
  3040.         stosb
  3041.         jmp    short parsepath_4
  3042. parsepath_5:
  3043.         push    cs
  3044.         pop    ds
  3045.         cmp    byte ptr es:[di-1],'\'  ;Append \ if necessary.
  3046.         je    parsepath_6
  3047.         mov    al,'\'
  3048.         stosb
  3049. parsepath_6:
  3050.         clc
  3051. parsepath_exit:
  3052.         pop    ds
  3053.         pop    si
  3054.         pop    dx
  3055.         pop    bx
  3056.         ret
  3057. parsepath_notfound:
  3058.         stc
  3059.         jmp    short parsepath_exit
  3060. parsepath    endp
  3061. parsepath_end      =      $
  3062.  
  3063. ;-----------------------------------------------------------------------------
  3064. ; INTCMD  Launches the shell ,usually COMMAND.COM, to run an internal command.
  3065. ; Entry   DS:SI - pointer to the ASCIIZ internal command to run.
  3066. ;-----------------------------------------------------------------------------
  3067. intcmd_launch    equ    [bx-8]
  3068. intcmd_getcom    equ    [bx-6]
  3069. intcmd_off    dw     0            ;Pointer to offset in COM file
  3070. intcmd_size    dw     offset intcmd_end - offset intcmd_start
  3071. intcmd_next    dw     0            ;Ptr to next routine to append
  3072. intcmd_lnks    dw     4
  3073. intcmd_start    =      $
  3074.         dw     offset launch_next    ;Call to load and run program.
  3075.         dw     offset getcom_next    ;Call to find shell name.
  3076.  
  3077. intcommand    proc    near
  3078.         assume    cs:code,ds:code,es:code,ss:code
  3079.         push    bx
  3080.         call    intcmd_1
  3081. intcmd_1:
  3082.         pop    bx            ;Get pointer to sub calls.
  3083.         mov    di,si            ;Copy ptr to command
  3084.         dec    di            ;Back up to cmd line size.
  3085.         mov    al,process_rc        ;Get and save return code
  3086.         push    ds
  3087.         push    ax
  3088.         call    intcmd_getcom        ;Get comspec string.
  3089.         call    cs:intcmd_launch    ;Run program.
  3090.         pop    ax
  3091.         pop    ds
  3092.         mov    process_rc,al        ;Restore return code
  3093.         pop    bx
  3094.         ret
  3095. intcommand    endp
  3096. intcmd_end    =    $
  3097.  
  3098. ;-----------------------------------------------------------------------------
  3099. ; GETCOMSPEC  Gets the name of the shell program running
  3100. ; Exit:   DS:SI - pointer to the ASCIIZ name of the shell porgram.
  3101. ;-----------------------------------------------------------------------------
  3102. getcom_srchenv    equ    [bx-6]
  3103. getcom_off    dw    0             ;Pointer to offset in COM file
  3104. getcom_size    dw    offset getcom_end - offset getcom_start
  3105. getcom_next    dw    0             ;Ptr to next routine to append
  3106. getcom_lnks    dw    2
  3107. getcom_start    =    $
  3108.         dw    offset searchenv_next     ;Call to search environment blk
  3109.  
  3110. getcomspec    proc    near
  3111.         assume    cs:code,ds:code,es:code,ss:code
  3112.         push    bx
  3113.         call    getcom_1
  3114. getcom_str    db    "COMSPEC"
  3115. getcom_1:
  3116.         pop    bx
  3117.         mov    dx,offset getcom_1 - offset getcom_str
  3118.         mov    si,bx
  3119.         call    getcom_srchenv        ;Get pointer to comspec string
  3120.         pop    bx
  3121.         ret
  3122. getcomspec    endp
  3123. getcom_end    =    $
  3124.  
  3125. ;----------------------------------------------------------------------------
  3126. ;LAUNCH PROG  Routine used to load and run programs.
  3127. ; Entry   DS:SI - pointer to the program name to run.
  3128. ;      ES:DI - pointer to the command line tail.
  3129. ; Exit      return code variable set.
  3130. ;----------------------------------------------------------------------------
  3131. launch_fcb1    equ    [bx]
  3132. launch_fcb2    equ    [bx+16]
  3133. launch_ptr    dw    0            ;Pointer to offset in COM file
  3134. launch_size    dw    offset launch_end - offset launch_start
  3135. launch_next    dw    0            ;Ptr to next routine to append
  3136. launch_lnks    dw    0            ;Bytes in the dependancy header ;Number of rou
  3137. launch_start    =    $
  3138.  
  3139. launch_code    proc    near
  3140.         assume    cs:code,ss:code
  3141.         push    bx
  3142.         call    launch_1        ;Push IP on stack
  3143.         db    0            ;Dummy FCB for program
  3144.         db    "DUMMY   FCB"
  3145.         db    0,0,0,0
  3146.         db    0            ;Dummy FCB for program
  3147.         db    "DUMMY   FCB"
  3148.         db    0,0,0,0
  3149. launch_1:
  3150.         pop    bx            ;Get pointer to local vars.
  3151.  
  3152.         push    ds
  3153.         push    es            ;Save stack ptr since it is not
  3154.         mov    com_stack_ptr,sp    ;  saved under DOS 2.x.
  3155. ;Parse first two parameters into FCBs.
  3156.         push    di            ;Save ptr to tail
  3157.         push    si            ;Save ptr to name
  3158.         mov    si,di            ;Copy ptr to cmd line
  3159.         inc    si            ;Skip size byte
  3160.         lea    di,launch_fcb1
  3161.         mov    ax,2903h        ;Parse FCB
  3162.         int    21h
  3163.         lea    di,launch_fcb2
  3164.         mov    ax,2903h
  3165.         int    21h
  3166.         pop    si
  3167.         pop    di
  3168.  
  3169.         push    cs            ;Create Parameter block on
  3170.         lea    dx,launch_fcb2        ;  the stack. Start with 2nd
  3171.         push    dx            ;  FCB.
  3172.         push    cs
  3173.         lea    dx,launch_fcb1
  3174.         push    dx
  3175.         push    cs            ;Push ptr to command line tail.
  3176.         push    di
  3177.         mov    ax,cs:[environment_seg]    ;Use env block set by prog.
  3178.         push    ax
  3179.         mov    bx,sp            ;Copy pointer to parameter blk
  3180.  
  3181.         mov    ax,4b00h        ;DOS EXEC program.
  3182.         mov    dx,si            ;Get pointer to filename
  3183.         int    21h
  3184.         mov    bp,offset data_start_ptr - offset init_code + 100h
  3185.         mov    bp,cs:[bp]
  3186.         mov    bx,cs            ;Reload BP to access local data
  3187.         cli
  3188.         mov    ss,bx            ;Restore stack
  3189.         mov    sp,com_stack_ptr
  3190.         sti
  3191.         cld                ;Restore default direction
  3192.         pop    es
  3193.         pop    ds
  3194. ;Get return code
  3195.         mov    ah,4dh            ;Get return code
  3196.         int    21h
  3197.         mov    process_rc,al        ;Save
  3198.         pop    bx
  3199.         ret
  3200. launch_code    endp
  3201. launch_end    =       $
  3202.  
  3203. ;----------------------------------------------------------------------------
  3204. ;GOTO  Routine to jump to a label pointed to by a cmd line parameter or
  3205. ;      environment variable.
  3206. ; Entry   DS:SI - pointer to label to find.
  3207. ;            DI - Wait flag/ptr. If <> 0, put goto address at pointer.
  3208. ; Exit      This routine does not return unless the label is not found.
  3209. ;----------------------------------------------------------------------------
  3210. goto_echomsg    equ    [bx-7]
  3211. goto_lblsrch    equ    [bx-5]
  3212. goto_ptr    dw    0            ;Pointer to offset in COM file
  3213. goto_size    dw    offset goto_end - offset goto_start
  3214. goto_next    dw    0            ;Ptr to next routine to append
  3215. goto_lnks    dw    4            ;Bytes in the dependancy header ;Number of routi
  3216. goto_start    =    $
  3217.         dw    echo_msg_next        ;Used to print error msg
  3218.         dw    lblsrch_next        ;Used to find label
  3219.  
  3220. goto_code    proc    near
  3221.         assume    cs:code,ds:code
  3222.         call    goto_1
  3223.         db    8 dup (" ")
  3224.         db    " Label not found",13,10,0
  3225. goto_1:
  3226.         pop    bx
  3227.         push    di            ;Save wait flag/pointer
  3228.         mov    di,bx            ;Load label into error msg
  3229.         xor    dx,dx            ;Get size of label as it is
  3230.         mov    cx,8            ;  copied into error msg.
  3231. goto_2:
  3232.         lodsb
  3233.         cmp    al," "
  3234.         jbe    goto_4
  3235.         cmp    al,'a'
  3236.         jb    goto_3
  3237.         and    al,0dfh         ;Capitalize label
  3238.         cmp    al,'Z'
  3239.         ja    goto_4
  3240. goto_3:
  3241.         stosb
  3242.         inc    dx
  3243.         loop    goto_2
  3244. goto_4:
  3245.         mov    cx,dx            ;Get size of label
  3246.         mov    si,bx            ;Get pointer to label
  3247.         mov    di,com_label_start    ;Get ptr to start of label list
  3248.         add    di,bp            ;Add offset of data
  3249.         push    bx            ;Save ptr to msg
  3250.         call    goto_lblsrch        ;Call search routine
  3251.         pop    dx            ;Restore ptr to message
  3252.         pop    si            ;Restore Wait flag/pointer
  3253.         jc    goto_5            ;CF set, label not found.
  3254.         mov    ax,[bx+2]        ;Get destination ptr
  3255.         or    si,si            ;See if delay flag <> 0
  3256.         je    goto_41            ;If 0, no delay
  3257.         mov    [bp+si],ax        ;Save ret addr at pointer
  3258.         ret
  3259. goto_41:
  3260.         pop    ax            ;Remove return address
  3261.         push    [bx+2]            ;Push new return address
  3262. goto_exit:
  3263.         ret
  3264. goto_5:
  3265.         mov    bx,dx            ;Set addressability to call
  3266.         call    goto_echomsg        ;Print error message.
  3267.         ret
  3268. goto_code    endp
  3269. goto_end         =    $
  3270.  
  3271. ;----------------------------------------------------------------------------
  3272. ;GOTO DLY  Routine used if goto statment is inside a FOR loop.  Since a for
  3273. ;      loop cannot be exited before it ends, this routine checks to see if
  3274. ;      the GOTO statment was ever executed. If so, we now can jump.
  3275. ; Entry   DS:SI - pointer to destination pointer. 0 = no jump.
  3276. ; Exit      This routine does not return unless the ptr = 0
  3277. ;----------------------------------------------------------------------------
  3278. gotodly_ptr    dw    0            ;Pointer to offset in COM file
  3279. gotodly_size    dw    offset gotodly_end - offset gotodly_start
  3280. gotodly_next    dw    0            ;Ptr to next routine to append
  3281. gotodly_lnks    dw    0            ;Bytes in the dependancy header ;Number of ro
  3282. gotodly_start    =    $
  3283.  
  3284. gotodly_code    proc    near
  3285.         assume    cs:code,ds:code
  3286.         xor    ax,ax            ;Get pointer, test if zero.
  3287.         or    ax,[si]            ;If zero, return.  If not
  3288.         je    gotodly_exit        ;  push the new destination
  3289.         pop    bx            ;  on the stack and return.
  3290.         push    ax
  3291. gotodly_exit:
  3292.         ret
  3293. gotodly_code    endp
  3294. gotodly_end     =         $
  3295.  
  3296. ;----------------------------------------------------------------------------
  3297. ;LABEL SEARCH Routine to search list of labels to determine goto destination.
  3298. ; Entry   ES:DI - pointer to the first entry in the list. (Assume ES = DS)
  3299. ;      DS:SI - pointer to label to find.
  3300. ;         CX - Length of label
  3301. ; Exit         BX - pointer to matching list entry, or last entry if not found.
  3302. ;         CF - Set if label not found.
  3303. ;----------------------------------------------------------------------------
  3304. lblsrch_ptr    dw    0            ;Pointer to offset in COM file
  3305. lblsrch_size    dw    offset lblsrch_end - offset lblsrch_start
  3306. lblsrch_next    dw    0            ;Ptr to next routine to append
  3307. lblsrch_lnks    dw    0            ;Bytes in the dependancy header ;Number of ro
  3308. lblsrch_start    =    $
  3309.  
  3310. lblsrch_code    proc    near
  3311.         assume    cs:code,ds:code
  3312.         push    si
  3313.         mov    dx,si            ;Save ptr to label
  3314.         mov    ax,cx            ;Save label length
  3315.         mov    bx,di            ;Get ptr to list
  3316. lblsrch_1:
  3317.         mov    di,bx
  3318.         add    di,4            ;Move to label string
  3319.         mov    si,dx            ;Get ptr to new label
  3320.         mov    cx,ax            ;Get length of label
  3321.         cmp    [di],cl         ;Compare lengths of the labels
  3322.         jne    lblsrch_2
  3323.         inc    di            ;Skip past length byte
  3324.         repe    cmpsb            ;Compare labels.
  3325.         je    lblsrch_4
  3326. lblsrch_2:
  3327.         cmp    word ptr [bx],-1    ;See if at end of list
  3328.         je    lblsrch_3
  3329.         add    bx,[bx]         ;Point to next label
  3330.         jmp    short lblsrch_1
  3331. lblsrch_3:
  3332.         stc                ;No label found.
  3333.         jmp    short lblsrch_exit
  3334. lblsrch_4:
  3335.         clc                ;Label found
  3336. lblsrch_exit:
  3337.         pop    si
  3338.         ret
  3339. lblsrch_code    endp
  3340. lblsrch_end    =    $
  3341.  
  3342. ;-----------------------------------------------------------------------------
  3343. ; IFEQUAL  Compares two strings.
  3344. ; Entry:  DS:SI - Pointer to first ASCIIZ String
  3345. ;      ES:DI - Pointer to second ASCIIZ String
  3346. ;         CX - Length of strings.
  3347. ; Exit:      CF - Clear if equal
  3348. ;-----------------------------------------------------------------------------
  3349. ifequal_off    dw     0            ;Pointer to offset in COM file
  3350. ifequal_size    dw     offset ifequal_end - offset ifequal_start
  3351. ifequal_next    dw     0            ;Ptr to next routine to append
  3352. ifequal_lnks    dw     0
  3353. ifequal_start    =      $
  3354.  
  3355. ifequal     proc    near
  3356.         assume    cs:code,ds:code,es:code,ss:code
  3357.         xor    cx,cx
  3358.         mov    cl,[si-1]        ;Get size of string
  3359.         cmp    cl,[di-1]        ;Compare sizes of strings
  3360.         jne    ifequal_notequal
  3361.         rep    cmpsb            ;Compare strings
  3362.         jne    ifequal_notequal
  3363.         clc
  3364.         ret
  3365. ifequal_notequal:
  3366.         stc
  3367.         ret
  3368. ifequal     endp
  3369. ifequal_end    =    $
  3370.  
  3371. ;-----------------------------------------------------------------------------
  3372. ; IFEXIST  Determines if a file exists.
  3373. ; Entry:  DS:SI - Pointer to ASCIIZ filename.
  3374. ;         DI - Pointer to buffer for disk transfer area.
  3375. ; Exit:      CF - Clear if file exists
  3376. ;         DI - IF file exists, points to filename.
  3377. ;-----------------------------------------------------------------------------
  3378. ifexist_off    dw     0            ;Pointer to offset in COM file
  3379. ifexist_size    dw     offset ifexist_end - offset ifexist_start
  3380. ifexist_next    dw     0            ;Ptr to next routine to append
  3381. ifexist_lnks    dw     0
  3382. ifexist_start    =      $
  3383.  
  3384. ifexist     proc    near
  3385.         assume    cs:code,ds:code,es:code,ss:code
  3386.         mov    dx,di
  3387.         mov    ah,1ah            ;Set DTA
  3388.         int    21h
  3389.  
  3390.         mov    dx,si            ;Copy pointer to filename
  3391.         xor    cx,cx            ;Normal attributes
  3392.         mov    ah,4eh            ;DOS Find First
  3393.         int    21h
  3394.         jc    ifexist_exit
  3395.         add    di,1eh            ;Point DI to filename in DTA
  3396.         clc
  3397. ifexist_exit:
  3398.         ret
  3399. ifexist     endp
  3400. ifexist_end    =    $
  3401.  
  3402. ;-----------------------------------------------------------------------------
  3403. ; IFERRLEV  Compares the value passed with the return code of the last
  3404. ;        program executed.
  3405. ; Entry:     SI - Pointer to ASCIIZ Error level.
  3406. ; Exit:      CF - Clear if process error level above or equal to SI
  3407. ;-----------------------------------------------------------------------------
  3408. iferrlev_off    dw     0            ;Pointer to offset in COM file
  3409. iferrlev_size    dw     offset iferrlev_end - offset iferrlev_start
  3410. iferrlev_next    dw     0            ;Ptr to next routine to append
  3411. iferrlev_lnks    dw     0
  3412. iferrlev_start    =      $
  3413.  
  3414. iferrlev    proc    near
  3415.         assume    cs:code,ds:code,es:code,ss:code
  3416.         xor    ax,ax            ;Convert ASCIIZ number into
  3417.         mov    bx,ax            ;  decimal
  3418. iferrlev_1:
  3419.         mov    bl,[si]         ;Convert error level number
  3420.         sub    bl,'0'                  ;  from ASCII to decimal.
  3421.         jb    iferrlev_2
  3422.         cmp    bl,9
  3423.         ja    iferrlev_2
  3424.         mov    dx,10
  3425.         mul    dx
  3426.         jc    iferrlev_2
  3427.         add    ax,bx            ;Add in digit
  3428.         inc    si
  3429.         jmp    short iferrlev_1
  3430. iferrlev_2:
  3431.         cmp    process_rc,al        ;Compare to last program
  3432.         ret
  3433. iferrlev    endp
  3434. iferrlev_end    =    $
  3435.  
  3436. ;-----------------------------------------------------------------------------
  3437. ; FORLOOP  Processes commands in a FOR loop.
  3438. ; Entry:     SI - Pointer to ASCIIZ set of parameters.
  3439. ;         DI - Pointer loop structure in data area
  3440. ;          LoopCnt    db     0    Member of the set to use
  3441. ;          FirstFlag    db     0    Indicates Find first/next
  3442. ; Exit:      CF - Set if FOR loop complete.
  3443. ;-----------------------------------------------------------------------------
  3444. forloop_getmem    equ    [bx-6]
  3445. forloop_savchr    equ    [bx]
  3446. forloop_eptr    equ    [bx+1]
  3447. forloop_dta       equ    [bx+3]
  3448. forloop_off    dw    0            ;Pointer to offset in COM file
  3449. forloop_size    dw    offset forloop_end - offset forloop_start
  3450. forloop_next    dw    0            ;Ptr to next routine to append
  3451. forloop_lnks    dw    2
  3452. forloop_start    =    $
  3453.         dw    getmember_next
  3454.  
  3455. forloop     proc    near
  3456.         assume    cs:code,ds:code,es:code,ss:code
  3457.         push    bx
  3458.         call    forloop_0
  3459.         db    0            ;Saved termaination character
  3460.         dw    0            ;Ptr to term character address
  3461.         db    43 dup (0)        ;Used for DTA
  3462. forloop_0:
  3463.         pop    bx
  3464.         push    si
  3465.         mov    si,forloop_eptr
  3466.         or    si,si
  3467.         je    forloop_01
  3468.         mov    al,forloop_savchr
  3469.         mov    byte ptr [si-1],al     ;Remove zero terminator
  3470. forloop_01:
  3471.         pop    si
  3472. ;
  3473. ;Set DTA. If 2nd time or later time looping on a member, use find next to
  3474. ;determine the string for this time through the loop.
  3475. ;
  3476.         lea    dx,forloop_dta
  3477.         mov    ah,1ah            ;Set DTA
  3478.         int    21h
  3479.  
  3480.         cmp    byte ptr [di+1],0    ;See if first time for member
  3481.         je    forloop_1
  3482.         mov    ah,4fh            ;Find next file
  3483.         int    21h
  3484.         jc    forloop_1        ;Not found, go to next member
  3485.         lea    dx,[bx+21h]        ;Point to filename in DTA
  3486.         jmp    short forloop_notdone    ;Execute loop body
  3487. ;
  3488. ;First time with this member of the set, if wildcards are in the member,
  3489. ;use DOS find first to get the loop string.
  3490. ;
  3491. forloop_1:
  3492.         mov    byte ptr [di+1],0    ;Clear first/next flag
  3493.         inc    byte ptr [di]        ;Look at next member of the set
  3494.         mov    dh,[di]         ;Get loop count
  3495.         call    forloop_getmem        ;Get member of set.  If no
  3496.         jc    forloop_done        ;  more members, loop done.
  3497.         mov    dx,si            ;Save pointer to member
  3498.         xor    ah,ah            ;Clear wildcard flag
  3499. forloop_2:
  3500.         lodsb                ;Scan set member to check for
  3501.         cmp    al,' '                  ;  any wildcard chars.
  3502.         jbe    forloop_4
  3503.         cmp    al,'?'
  3504.         jne    forloop_3
  3505.         inc    ah            ;Set wildcard found flag
  3506. forloop_3:
  3507.         cmp    al,'*'
  3508.         jne    forloop_2
  3509.         inc    ah            ;Set wildcard found flag
  3510.         jmp    short forloop_2
  3511. forloop_4:
  3512.         xor    al,al
  3513.         xchg    byte ptr [si-1],al    ;Set zero terminator.
  3514.         mov    forloop_savchr,al    ;Save char over written
  3515.         or    ah,ah            ;If no wildcards, execute
  3516.         je    forloop_notdone     ;Execute loop body
  3517.         mov    byte ptr [di+1],1    ;Set first/next flag
  3518.         xor    cx,cx            ;Normal attributes
  3519.         mov    ah,4eh            ;DOS find first
  3520.         int    21h
  3521.         jc    forloop_1        ;If not found, get next member
  3522.         lea    dx,[bx+1eh]        ;Set ptr to filename in DTA
  3523. forloop_notdone:
  3524.         mov    forloop_ptr,dx        ;Set loop data ptr
  3525.         mov    forloop_eptr,si
  3526.         clc
  3527. forloop_exit:
  3528.         pop    bx
  3529.         ret
  3530. forloop_done:
  3531.         mov    word ptr [di],0     ;Clear loop variables
  3532.         mov    word ptr forloop_eptr,0
  3533.         stc
  3534.         jmp    short forloop_exit
  3535. forloop     endp
  3536. forloop_end    =    $
  3537.  
  3538. ;-----------------------------------------------------------------------------
  3539. ; FINDENV  Finds the environment block of the local command processor.
  3540. ; Exit:    Variable environment_seg set with segment of the environment.
  3541. ;-----------------------------------------------------------------------------
  3542. findenv_off    dw    0             ;Pointer to offset in COM file
  3543. findenv_size    dw    offset findenv_end - offset findenv_start
  3544. findenv_next    dw    0             ;Ptr to next routine to append
  3545. findenv_lnks    dw    0
  3546. findenv_start    =    $
  3547.  
  3548. findenv     proc    near
  3549.         assume    cs:code,ds:code,es:code,ss:code
  3550.         push    bx
  3551.         push    es
  3552.  
  3553.         mov    ax,ds:[2ch]        ;Get default env
  3554.         cmp    environment_seg,ax    ;Check to see if already
  3555.         jne    findenv_exit        ;  found.
  3556.         push    cs
  3557.         pop    es
  3558. findenv_1:
  3559.             mov     ax,es:[16h]             ;Get parent's PSP
  3560.         mov    dx,ax            ;Save PSP segment
  3561.         push    ax
  3562.         dec    ax            ;Point to mcb
  3563.         mov    es,ax
  3564.             cmp     byte ptr es:[0],"M"     ;check for mcb signature
  3565.         pop    es
  3566.             jne     findenv_exit
  3567.  
  3568.         cmp    dx,es:[16h]        ;See if PSP is own parent
  3569.         jne    findenv_1        ;No, keep looking
  3570.  
  3571.         mov    cx,30
  3572.         mov    es,ax
  3573. findenv_2:
  3574.             add     ax,es:[3]               ;Add size of memory block
  3575.         inc    ax
  3576.             mov     es,ax
  3577.  
  3578.             cmp     byte ptr es:[0],"M"     ;check for mcb signature
  3579.             jne     findenv_exit
  3580.             cmp     dx,es:[1]               ;See if this owned by cmd proc
  3581.             je      findenv_3
  3582.             loop    findenv_2
  3583.             jmp     short findenv_exit
  3584. findenv_3:
  3585.         inc    ax
  3586. findenv_found:
  3587.         mov    environment_seg,ax    ;Save pointer to master env
  3588. findenv_exit:
  3589.         pop    es
  3590.         pop    bx
  3591.         ret
  3592. findenv     endp
  3593. findenv_end    =    $
  3594.  
  3595. ;-----------------------------------------------------------------------------
  3596. ; SET_ENV  Sets/resets environment variables.
  3597. ; Entry:  DS:SI - pointer to ASCII string containing the environment variable
  3598. ;          and, optionally, the string to assign.
  3599. ;                 If no string specified, the environment is dumped to the
  3600. ;                 screen.
  3601. ;            DI - Flag to indicate setting of PATH and PROMPT vars
  3602. ;                 0 = Normal Env var, 1 = PROMPT var, 2 = PATH var.
  3603. ;-----------------------------------------------------------------------------
  3604. setenv_findenv    equ    [bx-10]
  3605. setenv_echo    equ    [bx-8]
  3606. setenv_serchenv equ    [bx-6]
  3607. setenv_pathflag    equ    [bx]
  3608. setenv_varlen     equ    [bx+1]
  3609. setenv_fullmsg    equ    [bx+2]
  3610. setenv_crmsg      equ    [bx+29]
  3611. setenv_nopath    equ    [bx+32]
  3612. setenv_off    dw    0            ;Pointer to offset in COM file
  3613. setenv_size    dw    offset setenv_end - offset setenv_start
  3614. setenv_next    dw    0            ;Ptr to next routine to append
  3615. setenv_lnks    dw    6
  3616. setenv_start    =    $
  3617.         dw    offset findenv_next    ;Call to find the master env
  3618.         dw    offset echo_msg_next    ;Call to print line.
  3619.         dw    offset searchenv_next    ;Call to search environment blk
  3620.  
  3621. set_env     proc near
  3622.         assume    ds:nothing,es:nothing
  3623.         push    bx
  3624.         call    setenv_1
  3625.         db    0            ;PATH/PROMPT flag storage
  3626.         db    0            ;Var length.
  3627.         db    "Out of environment space",13,10,0
  3628.         db    13,10,0
  3629.         db    "No Path",0
  3630. setenv_1:
  3631.         pop    bx            ;Set up local addressing
  3632.         mov    ax,di
  3633.         xchg    al,ah
  3634.         mov    setenv_pathflag,ah
  3635.         push    ax
  3636.         call    setenv_findenv        ;Find master env block
  3637.         pop    ax
  3638.         push    bp
  3639.         push    es
  3640. ;See if we need to simply print the PATH statment.
  3641.         cmp    ah,3
  3642.         jne    setenv_19
  3643.         mov    dx,4
  3644.         call    setenv_serchenv     ;Get pointer to variable
  3645.         jnc    setenv_11
  3646.         lea    si,setenv_nopath    ;If path string not found,
  3647.         push    cs            ;  print no path msg.
  3648.         pop    ds
  3649.         jmp    short setenv_12
  3650. setenv_11:
  3651.         sub    si,5            ;Back up to start of PATH
  3652. setenv_12:
  3653.         call    cs:setenv_echo        ;Print string
  3654.         push    cs
  3655.         pop    ds
  3656.         lea    si,setenv_crmsg        ;Append CR.
  3657.         call    setenv_echo
  3658.         jmp    setenv_8
  3659. setenv_19:
  3660.         mov    cx,BUFF_SIZE
  3661.         xor    dx,dx
  3662.         push    si            ;Save ptr to new env var
  3663.         mov    di,si
  3664. setenv_2:
  3665.         lodsb
  3666.         or     ah,ah            ;See if PATH or PROMPT
  3667.         je    setenv_23
  3668.         cmp    al," "            ;If PATH or PROMPT statments,
  3669.         jne    setenv_23        ;  remove any spaces between
  3670.         mov    al,"="            ;  variable and assignment.
  3671.         push    di
  3672.         stosb
  3673. setenv_20:
  3674.         lodsb                ;Scan past equal sign
  3675.         cmp    al," "
  3676.         je    setenv_20
  3677.         cmp    al,"="
  3678.         je    setenv_20
  3679. setenv_21:
  3680.         stosb
  3681.         or    al,al
  3682.         je    setenv_22
  3683.         lodsb                ;Remove spaces in set string.
  3684.         jmp    short setenv_21
  3685. setenv_22:
  3686.         pop    di
  3687.         jmp    short setenv_4
  3688. setenv_23:
  3689.         or     al,al
  3690.         je    setenv_4
  3691.         cmp    al,"="                  ;Scan until end of variable
  3692.         je    setenv_4        ;  found.
  3693.         cmp    al,'a'
  3694.         jb    setenv_3
  3695.         cmp    al,'z'
  3696.         ja    setenv_3
  3697.         and    al,0dfh         ;Capitalize variable
  3698. setenv_3:
  3699.         cmp    al," "            ;Keep a count of non-space
  3700.         jbe    setenv_31        ;  characters.
  3701.         inc    dh
  3702. setenv_31:
  3703.         stosb
  3704.         inc    dl            ;Var length count.
  3705.         loop    setenv_2
  3706. setenv_4:
  3707.         pop    si
  3708. ;
  3709. ;If no characters after SET, dump env vars to screen.
  3710. ;
  3711.         mov    setenv_varlen,dl    ;Save length of env var.
  3712.         mov    al,dh
  3713.         xor    dh,dh
  3714.         or    dh,dh            ;See if path or prompt
  3715.         jne    setenv_40
  3716. setenv_40:
  3717.         or    al,al            ;If second Zero, end of vars.
  3718.         jne    setenv_48
  3719.         push    ds
  3720.         mov    ds,cs:[environment_seg]    ;Get segment of environment
  3721.         xor    si,si
  3722.         lea    di,setenv_crmsg        ;Get address of CR string
  3723.         mov    cx,cs
  3724. setenv_41:
  3725.         call    cs:setenv_echo        ;Print var
  3726.         push    ds
  3727.         push    si
  3728.         mov     ds,cx
  3729.         mov     si,di
  3730.         call    cs:setenv_echo        ;Print CR
  3731.         pop    si
  3732.         pop    ds
  3733.         cmp    byte ptr ds:[si],0    ;If next char 0, end of block
  3734.         jne    setenv_41
  3735.         pop    ds
  3736.         jmp    setenv_8
  3737. ;
  3738. ;Set or Clear env var.
  3739. ;
  3740. setenv_48:
  3741.         mov    ax,si
  3742.         inc    di
  3743.         cmp    byte ptr cs:[di]," "    ;If nothing past '=' then
  3744.         jae    setenv_49        ;  simply erase var from env.
  3745.         xor    ax,ax
  3746. setenv_49:
  3747.         push    ax            ;Save set/erase flag
  3748.         call    setenv_serchenv     ;Get pointer to variable
  3749.         pop    dx
  3750.         push    ds            ;ES = env segment
  3751.         pop    es
  3752.         mov    di,si            ;Copy pointer to variable
  3753.         jc    setenv_61
  3754.  
  3755.         xor    al,al            ;Scan backwards to find start
  3756.         std                ;  of var name
  3757.         mov    cx,256
  3758.         repne    scasb
  3759.         inc    di
  3760.         inc    di
  3761.         push    di
  3762.         cld                ;Scan forward to find end of
  3763.         mov    cx,256            ;  variable.
  3764.         repne    scasb
  3765.         mov    si,di
  3766.         pop    di
  3767.         xor    ah,ah
  3768. setenv_5:
  3769.         lodsb                ;Move byte from past var to
  3770.         stosb                ;  cover up current assignment
  3771.         or    ah,al            ;If two zeros in a row then
  3772.         je    setenv_6        ;  end of env vars.
  3773.         mov    ah,al
  3774.         jmp    short setenv_5
  3775. setenv_6:
  3776.         dec    di            ;Back up before last zero
  3777. setenv_61:
  3778.         push    cs
  3779.         pop    ds
  3780.         mov    si,dx            ;Get back ptr to env var
  3781.         or    si,si            ;See if var assignment
  3782.         je    setenv_8
  3783.  
  3784.         push    es            ;Get size of the environment
  3785.         mov    ax,es            ;  block by reading the size
  3786.         dec    ax            ;  in the memory control block.
  3787.         mov    es,ax
  3788.         mov    bp,es:[3]
  3789.         mov    cl,4
  3790.         shl    bp,cl            ;Convert to bytes.
  3791.         dec    bp
  3792.         dec    bp
  3793.         pop    es
  3794.         xor    ax,ax            ;See if there is room in the
  3795.         mov    al,setenv_varlen    ;  env block for the var name.
  3796.         inc    al            ;  If not, don't even start.
  3797.         add    ax,di            ;  If room for name, copy as
  3798.         cmp    ax,bp            ;  much of the var as possible
  3799.         jae    setenv_72
  3800.         mov    ah,setenv_pathflag    ;Get pathflag byte
  3801. setenv_7:
  3802.         cmp    di,bp            ;Check for end of env block.
  3803.         jae    setenv_72
  3804.         lodsb                ;Copy new env var
  3805.         cmp    ah,2
  3806.         jne    setenv_71        ;If PATH var, make upper case.
  3807.         cmp    al,'a'
  3808.         jb     setenv_71
  3809.         cmp    al,'z'
  3810.         ja    setenv_71
  3811.         and    al,0dfh
  3812. setenv_71:
  3813.         stosb
  3814.         or    al,al            ;Check for end of variable.
  3815.         jne    setenv_7
  3816.         stosb
  3817.         jmp    short setenv_8
  3818. setenv_72:
  3819.         xor    al,al
  3820.         stosb
  3821.         push    cs
  3822.         pop    es
  3823.         lea    si,setenv_fullmsg    ;If environment block full,
  3824.         call    setenv_echo        ;  print message.
  3825. setenv_8:
  3826.         pop    es
  3827.         pop    bp
  3828.         pop    bx
  3829.         ret
  3830. set_env     endp
  3831. setenv_end    =    $
  3832.  
  3833. ;-----------------------------------------------------------------------------
  3834. ; REDIROO  Opens a file for output redirection.
  3835. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3836. ;         DI - 0  open new file, 1 append to existing file.
  3837. ;-----------------------------------------------------------------------------
  3838. rediroo_off    dw    0            ;Pointer to offset in COM file
  3839. rediroo_size    dw    offset rediroo_end - offset rediroo_start
  3840. rediroo_next    dw    0            ;Ptr to next routine to append
  3841. rediroo_lnks    dw    0
  3842. rediroo_start    =    $
  3843.  
  3844. rediroo     proc near
  3845.         assume    ds:nothing,es:nothing
  3846.  
  3847.         mov    word ptr stdout_hdl,-1    ;Clear handle
  3848.         mov    dx,si            ;Get ptr to outfile file
  3849.         xor    cx,cx            ;Normal attributes
  3850.         mov    ax,3c02h        ;Create file
  3851.         or    di,di            ;See if append or new file
  3852.         je    rediroo_2
  3853.         inc    ah            ;Open file
  3854. rediroo_2:
  3855.         int    21h
  3856.         jc    rediroo_exit
  3857.         mov    bx,ax            ;Copy file handle
  3858.         or    di,di
  3859.         je    rediroo_3
  3860.         mov    ax,4202h        ;Move file ptr to end of file
  3861.         xor    dx,dx
  3862.         mov    cx,dx
  3863.         int    21h
  3864.         jc    rediroo_exit
  3865. rediroo_3:
  3866.         mov    outfile_hdl,bx        ;Save output file handle
  3867.         push    bx
  3868.         mov    ah,45h            ;Duplicate output handle
  3869.         mov    bx,1            ;Std output handle
  3870.         int    21h
  3871.         mov    stdout_hdl,ax        ;Save dup std output handle
  3872.  
  3873.         mov    cx,1
  3874.         pop    bx
  3875.         mov    ah,46h            ;Force dup file handle
  3876.         int    21h
  3877. rediroo_exit:
  3878.         ret
  3879. rediroo     endp
  3880. rediroo_end    =    $
  3881.  
  3882. ;-----------------------------------------------------------------------------
  3883. ; REDIRCO  Closes a file used for output redirection.
  3884. ;-----------------------------------------------------------------------------
  3885. redirco_off    dw    0            ;Pointer to offset in COM file
  3886. redirco_size    dw    offset redirco_end - offset redirco_start
  3887. redirco_next    dw    0            ;Ptr to next routine to append
  3888. redirco_lnks    dw    0
  3889. redirco_start    =    $
  3890.  
  3891. redirco     proc near
  3892.         assume    ds:nothing,es:nothing
  3893.         cmp    word ptr stdout_hdl,-1    ;If error on redirect, skip
  3894.         je    redirco_exit        ;  restore.
  3895.  
  3896.         mov    ah,46h            ;Force restore of std out
  3897.         mov    bx,stdout_hdl
  3898.         mov    cx,1
  3899.         int    21h
  3900.  
  3901.         mov    ah,3eh            ;Close file
  3902.         mov    bx,outfile_hdl        ;Get output file handle
  3903.         int    21h
  3904. redirco_exit:
  3905.         ret
  3906. redirco     endp
  3907. redirco_end    =    $
  3908.  
  3909. ;-----------------------------------------------------------------------------
  3910. ; REDIROI  Opens a file for input redirection.
  3911. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3912. ;         DI - 0  open new file, 1 append to existing file.
  3913. ;-----------------------------------------------------------------------------
  3914. rediroi_off    dw    0            ;Pointer to offset in COM file
  3915. rediroi_size    dw    offset rediroi_end - offset rediroi_start
  3916. rediroi_next    dw    0            ;Ptr to next routine to append
  3917. rediroi_lnks    dw    0
  3918. rediroi_start    =    $
  3919.  
  3920. rediroi     proc near
  3921.         assume    ds:nothing,es:nothing
  3922.  
  3923.         mov    word ptr stdin_hdl,-1    ;Clear handle
  3924.         mov    dx,si            ;Get ptr to outfile file
  3925.         mov    ax,3d00h        ;Open file, Read only
  3926.         int    21h
  3927.         jc    rediroi_exit
  3928.         mov    infile_hdl,ax        ;Save input file handle
  3929.         push    ax
  3930.  
  3931.         mov    ah,45h            ;Duplicate input handle
  3932.         xor    bx,bx
  3933.         int    21h
  3934.         mov    stdin_hdl,ax        ;Save dup std input handle
  3935.  
  3936.         xor    cx,cx
  3937.         pop    bx
  3938.         mov    ah,46h            ;Force dup file handle
  3939.         int    21h
  3940. rediroi_exit:
  3941.         ret
  3942. rediroi     endp
  3943. rediroi_end    =    $
  3944.  
  3945. ;-----------------------------------------------------------------------------
  3946. ; REDIRCI  Closes a file used for input redirection.
  3947. ;-----------------------------------------------------------------------------
  3948. redirci_off    dw    0            ;Pointer to offset in COM file
  3949. redirci_size    dw    offset redirci_end - offset redirci_start
  3950. redirci_next    dw    0            ;Ptr to next routine to append
  3951. redirci_lnks    dw    0
  3952. redirci_start    =    $
  3953.  
  3954. redirci     proc near
  3955.         assume    ds:nothing,es:nothing
  3956.         cmp    word ptr stdin_hdl,-1    ;If error on redirect, skip
  3957.         je    redirci_exit        ;  restore.
  3958.  
  3959.         mov    ah,46h            ;Force restore of std in hdl
  3960.         xor    cx,cx
  3961.         mov    bx,stdin_hdl
  3962.         int    21h
  3963.  
  3964.         mov    ah,3eh            ;Close file
  3965.         mov    bx,infile_hdl        ;Get input file handle
  3966.         int    21h
  3967. redirci_exit:
  3968.         ret
  3969. redirci     endp
  3970. redirci_end    =    $
  3971.  
  3972. ;-----------------------------------------------------------------------------
  3973. ; REDIRDEL Deletes piping file.
  3974. ; Entry:  DS:SI - pointer to ASCII filename to delete.
  3975. ;-----------------------------------------------------------------------------
  3976. redirdel_off    dw    0            ;Pointer to offset in COM file
  3977. redirdel_size    dw    offset redirdel_end - offset redirdel_start
  3978. redirdel_next    dw    0            ;Ptr to next routine to append
  3979. redirdel_lnks    dw    0
  3980. redirdel_start    =    $
  3981.  
  3982. redirdel     proc near
  3983.         assume    ds:nothing,es:nothing
  3984.  
  3985.         mov    dx,si            ;Copy pointer to filename
  3986.         mov    ah,41h            ;Delete file
  3987.         int    21h
  3988.         ret
  3989. redirdel     endp
  3990. redirdel_end    =    $
  3991.  
  3992. initialize    endp
  3993.         even                ;compiler stack on word boundry
  3994. end_of_code    =    $
  3995. code        ends
  3996.  
  3997. end  main
  3998.  
  3999.